LCOV - code coverage report
Current view: top level - src/compiler - access-info.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 237 262 90.5 %
Date: 2019-01-20 Functions: 17 29 58.6 %

          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/compiler/access-info.h"
       8             : 
       9             : #include "src/accessors.h"
      10             : #include "src/compiler/compilation-dependencies.h"
      11             : #include "src/compiler/type-cache.h"
      12             : #include "src/field-index-inl.h"
      13             : #include "src/field-type.h"
      14             : #include "src/ic/call-optimization.h"
      15             : #include "src/objects-inl.h"
      16             : #include "src/objects/cell-inl.h"
      17             : #include "src/objects/module-inl.h"
      18             : #include "src/objects/struct-inl.h"
      19             : #include "src/objects/templates.h"
      20             : 
      21             : namespace v8 {
      22             : namespace internal {
      23             : namespace compiler {
      24             : 
      25             : namespace {
      26             : 
      27       37661 : bool CanInlineElementAccess(Handle<Map> map) {
      28       37661 :   if (!map->IsJSObjectMap()) return false;
      29       36053 :   if (map->is_access_check_needed()) return false;
      30       36053 :   if (map->has_indexed_interceptor()) return false;
      31             :   ElementsKind const elements_kind = map->elements_kind();
      32       36043 :   if (IsFastElementsKind(elements_kind)) return true;
      33       12086 :   if (IsFixedTypedArrayElementsKind(elements_kind) &&
      34       12086 :       elements_kind != BIGUINT64_ELEMENTS &&
      35             :       elements_kind != BIGINT64_ELEMENTS) {
      36             :     return true;
      37             :   }
      38        1628 :   return false;
      39             : }
      40             : 
      41             : 
      42      252561 : bool CanInlinePropertyAccess(Handle<Map> map) {
      43             :   // We can inline property access to prototypes of all primitives, except
      44             :   // the special Oddball ones that have no wrapper counterparts (i.e. Null,
      45             :   // Undefined and TheHole).
      46             :   STATIC_ASSERT(ODDBALL_TYPE == LAST_PRIMITIVE_TYPE);
      47      252561 :   if (map->IsBooleanMap()) return true;
      48      252031 :   if (map->instance_type() < LAST_PRIMITIVE_TYPE) return true;
      49      715574 :   return map->IsJSObjectMap() && !map->is_dictionary_map() &&
      50      474696 :          !map->has_named_interceptor() &&
      51             :          // TODO(verwaest): Whitelist contexts to which we have access.
      52             :          !map->is_access_check_needed();
      53             : }
      54             : 
      55             : }  // namespace
      56             : 
      57             : 
      58           0 : std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
      59           0 :   switch (access_mode) {
      60             :     case AccessMode::kLoad:
      61           0 :       return os << "Load";
      62             :     case AccessMode::kStore:
      63           0 :       return os << "Store";
      64             :     case AccessMode::kStoreInLiteral:
      65           0 :       return os << "StoreInLiteral";
      66             :   }
      67           0 :   UNREACHABLE();
      68             : }
      69             : 
      70             : ElementAccessInfo::ElementAccessInfo() = default;
      71             : 
      72           0 : ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps,
      73             :                                      ElementsKind elements_kind)
      74       22614 :     : elements_kind_(elements_kind), receiver_maps_(receiver_maps) {}
      75             : 
      76             : // static
      77           0 : PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps,
      78             :                                                 MaybeHandle<JSObject> holder) {
      79           0 :   return PropertyAccessInfo(kNotFound, holder, receiver_maps);
      80             : }
      81             : 
      82             : // static
      83           0 : PropertyAccessInfo PropertyAccessInfo::DataConstant(
      84             :     MapHandles const& receiver_maps, Handle<Object> constant,
      85             :     MaybeHandle<JSObject> holder) {
      86           0 :   return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
      87             : }
      88             : 
      89             : // static
      90           0 : PropertyAccessInfo PropertyAccessInfo::DataField(
      91             :     PropertyConstness constness, MapHandles const& receiver_maps,
      92             :     FieldIndex field_index, MachineRepresentation field_representation,
      93             :     Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
      94             :     MaybeHandle<Map> transition_map) {
      95             :   Kind kind =
      96       26705 :       constness == PropertyConstness::kConst ? kDataConstantField : kDataField;
      97             :   return PropertyAccessInfo(kind, holder, transition_map, field_index,
      98             :                             field_representation, field_type, field_map,
      99           0 :                             receiver_maps);
     100             : }
     101             : 
     102             : // static
     103           0 : PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
     104             :     MapHandles const& receiver_maps, Handle<Object> constant,
     105             :     MaybeHandle<JSObject> holder) {
     106           0 :   return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
     107             : }
     108             : 
     109             : // static
     110           0 : PropertyAccessInfo PropertyAccessInfo::ModuleExport(
     111             :     MapHandles const& receiver_maps, Handle<Cell> cell) {
     112             :   return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell,
     113           0 :                             receiver_maps);
     114             : }
     115             : 
     116             : // static
     117           0 : PropertyAccessInfo PropertyAccessInfo::StringLength(
     118             :     MapHandles const& receiver_maps) {
     119             :   return PropertyAccessInfo(kStringLength, MaybeHandle<JSObject>(),
     120           0 :                             receiver_maps);
     121             : }
     122             : 
     123        2961 : PropertyAccessInfo::PropertyAccessInfo()
     124             :     : kind_(kInvalid),
     125             :       field_representation_(MachineRepresentation::kNone),
     126      475869 :       field_type_(Type::None()) {}
     127             : 
     128           0 : PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
     129             :                                        MapHandles const& receiver_maps)
     130             :     : kind_(kind),
     131             :       receiver_maps_(receiver_maps),
     132             :       holder_(holder),
     133             :       field_representation_(MachineRepresentation::kNone),
     134       17760 :       field_type_(Type::None()) {}
     135             : 
     136           0 : PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
     137             :                                        Handle<Object> constant,
     138             :                                        MapHandles const& receiver_maps)
     139             :     : kind_(kind),
     140             :       receiver_maps_(receiver_maps),
     141             :       constant_(constant),
     142             :       holder_(holder),
     143             :       field_representation_(MachineRepresentation::kNone),
     144      162718 :       field_type_(Type::Any()) {}
     145             : 
     146           0 : PropertyAccessInfo::PropertyAccessInfo(
     147             :     Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
     148             :     FieldIndex field_index, MachineRepresentation field_representation,
     149             :     Type field_type, MaybeHandle<Map> field_map,
     150             :     MapHandles const& receiver_maps)
     151             :     : kind_(kind),
     152             :       receiver_maps_(receiver_maps),
     153             :       transition_map_(transition_map),
     154             :       holder_(holder),
     155             :       field_index_(field_index),
     156             :       field_representation_(field_representation),
     157             :       field_type_(field_type),
     158      106181 :       field_map_(field_map) {}
     159             : 
     160       12205 : bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
     161             :                                AccessMode access_mode, Zone* zone) {
     162       12205 :   if (this->kind_ != that->kind_) return false;
     163       11863 :   if (this->holder_.address() != that->holder_.address()) return false;
     164             : 
     165       10582 :   switch (this->kind_) {
     166             :     case kInvalid:
     167             :       break;
     168             : 
     169             :     case kDataField:
     170             :     case kDataConstantField: {
     171             :       // Check if we actually access the same field (we use the
     172             :       // GetFieldAccessStubKey method here just like the ICs do
     173             :       // since that way we only compare the relevant bits of the
     174             :       // field indices).
     175        7836 :       if (this->field_index_.GetFieldAccessStubKey() ==
     176             :           that->field_index_.GetFieldAccessStubKey()) {
     177        7005 :         switch (access_mode) {
     178             :           case AccessMode::kLoad: {
     179        4418 :             if (this->field_representation_ != that->field_representation_) {
     180         746 :               if (!IsAnyTagged(this->field_representation_) ||
     181             :                   !IsAnyTagged(that->field_representation_)) {
     182             :                 return false;
     183             :               }
     184         373 :               this->field_representation_ = MachineRepresentation::kTagged;
     185             :             }
     186        4418 :             if (this->field_map_.address() != that->field_map_.address()) {
     187         244 :               this->field_map_ = MaybeHandle<Map>();
     188             :             }
     189             :             break;
     190             :           }
     191             :           case AccessMode::kStore:
     192             :           case AccessMode::kStoreInLiteral: {
     193             :             // For stores, the field map and field representation information
     194             :             // must match exactly, otherwise we cannot merge the stores. We
     195             :             // also need to make sure that in case of transitioning stores,
     196             :             // the transition targets match.
     197        5126 :             if (this->field_map_.address() != that->field_map_.address() ||
     198        5006 :                 this->field_representation_ != that->field_representation_ ||
     199             :                 this->transition_map_.address() !=
     200             :                     that->transition_map_.address()) {
     201             :               return false;
     202             :             }
     203             :             break;
     204             :           }
     205             :         }
     206             :         // Merge the field type.
     207             :         this->field_type_ =
     208        4677 :             Type::Union(this->field_type_, that->field_type_, zone);
     209             :         // Merge the receiver maps.
     210             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     211             :                                     that->receiver_maps_.begin(),
     212       11891 :                                     that->receiver_maps_.end());
     213        4677 :         return true;
     214             :       }
     215             :       return false;
     216             :     }
     217             : 
     218             :     case kDataConstant:
     219             :     case kAccessorConstant: {
     220             :       // Check if we actually access the same constant.
     221        2540 :       if (this->constant_.address() == that->constant_.address()) {
     222             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     223             :                                     that->receiver_maps_.begin(),
     224        2331 :                                     that->receiver_maps_.end());
     225        2331 :         return true;
     226             :       }
     227             :       return false;
     228             :     }
     229             : 
     230             :     case kNotFound:
     231             :     case kStringLength: {
     232             :       this->receiver_maps_.insert(this->receiver_maps_.end(),
     233             :                                   that->receiver_maps_.begin(),
     234         206 :                                   that->receiver_maps_.end());
     235         206 :       return true;
     236             :     }
     237             :     case kModuleExport: {
     238             :       return false;
     239             :     }
     240             :   }
     241             : 
     242           0 :   UNREACHABLE();
     243             : }
     244             : 
     245           7 : Handle<Cell> PropertyAccessInfo::export_cell() const {
     246             :   DCHECK_EQ(kModuleExport, kind_);
     247           7 :   return Handle<Cell>::cast(constant_);
     248             : }
     249             : 
     250      169032 : AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
     251             :                                      CompilationDependencies* dependencies,
     252             :                                      Handle<Context> native_context, Zone* zone)
     253             :     : broker_(broker),
     254             :       dependencies_(dependencies),
     255             :       native_context_(native_context),
     256             :       isolate_(native_context->GetIsolate()),
     257      169032 :       type_cache_(TypeCache::Get()),
     258      507096 :       zone_(zone) {
     259             :   DCHECK(native_context->IsNativeContext());
     260      169032 : }
     261             : 
     262             : 
     263       10412 : bool AccessInfoFactory::ComputeElementAccessInfo(
     264             :     Handle<Map> map, AccessMode access_mode, ElementAccessInfo* access_info) {
     265             :   // Check if it is safe to inline element access for the {map}.
     266       10412 :   if (!CanInlineElementAccess(map)) return false;
     267             :   ElementsKind const elements_kind = map->elements_kind();
     268       28095 :   *access_info = ElementAccessInfo(MapHandles{map}, elements_kind);
     269        9365 :   return true;
     270             : }
     271             : 
     272       22967 : bool AccessInfoFactory::ComputeElementAccessInfos(
     273       29154 :     MapHandles const& maps, AccessMode access_mode,
     274       29162 :     ZoneVector<ElementAccessInfo>* access_infos) {
     275       22967 :   if (access_mode == AccessMode::kLoad) {
     276             :     // For polymorphic loads of similar elements kinds (i.e. all tagged or all
     277             :     // double), always use the "worst case" code without a transition.  This is
     278             :     // much faster than transitioning the elements to the worst case, trading a
     279             :     // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
     280             :     ElementAccessInfo access_info;
     281       14473 :     if (ConsolidateElementLoad(maps, &access_info)) {
     282       13249 :       access_infos->push_back(access_info);
     283       13249 :       return true;
     284        1224 :     }
     285             :   }
     286             : 
     287             :   // Collect possible transition targets.
     288             :   MapHandles possible_transition_targets;
     289        9718 :   possible_transition_targets.reserve(maps.size());
     290       30702 :   for (Handle<Map> map : maps) {
     291       22532 :     if (Map::TryUpdate(isolate(), map).ToHandle(&map)) {
     292       32515 :       if (CanInlineElementAccess(map) &&
     293       17715 :           IsFastElementsKind(map->elements_kind()) &&
     294             :           GetInitialFastElementsKind() != map->elements_kind()) {
     295        5149 :         possible_transition_targets.push_back(map);
     296             :       }
     297             :     }
     298             :   }
     299             : 
     300             :   // Separate the actual receiver maps and the possible transition sources.
     301             :   MapHandles receiver_maps;
     302        9718 :   receiver_maps.reserve(maps.size());
     303        9718 :   MapTransitionList transitions(maps.size());
     304       30702 :   for (Handle<Map> map : maps) {
     305       22532 :     if (Map::TryUpdate(isolate(), map).ToHandle(&map)) {
     306             :       // Don't generate elements kind transitions from stable maps.
     307       22532 :       Map transition_target = map->is_stable()
     308             :                                   ? Map()
     309             :                                   : map->FindElementsKindTransitionedMap(
     310       17330 :                                         isolate(), possible_transition_targets);
     311       11266 :       if (transition_target.is_null()) {
     312       10700 :         receiver_maps.push_back(map);
     313             :       } else {
     314             :         transitions.push_back(
     315        1132 :             std::make_pair(map, handle(transition_target, isolate())));
     316             :       }
     317             :     }
     318             :   }
     319             : 
     320       28801 :   for (Handle<Map> receiver_map : receiver_maps) {
     321             :     // Compute the element access information.
     322             :     ElementAccessInfo access_info;
     323       10412 :     if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
     324        1047 :       return false;
     325             :     }
     326             : 
     327             :     // Collect the possible transitions for the {receiver_map}.
     328       31154 :     for (auto transition : transitions) {
     329       12424 :       if (transition.second.is_identical_to(receiver_map)) {
     330         538 :         access_info.transitions().push_back(transition);
     331             :       }
     332             :     }
     333             : 
     334             :     // Schedule the access information.
     335        9365 :     access_infos->push_back(access_info);
     336        9365 :   }
     337        8671 :   return true;
     338             : }
     339             : 
     340             : 
     341      157438 : bool AccessInfoFactory::ComputePropertyAccessInfo(
     342             :     Handle<Map> map, Handle<Name> name, AccessMode access_mode,
     343      565761 :     PropertyAccessInfo* access_info) {
     344      157438 :   CHECK(name->IsUniqueName());
     345             : 
     346             :   // Check if it is safe to inline property access for the {map}.
     347      157438 :   if (!CanInlinePropertyAccess(map)) return false;
     348             : 
     349             :   // Compute the receiver type.
     350             :   Handle<Map> receiver_map = map;
     351             : 
     352             :   // We support fast inline cases for certain JSObject getters.
     353      267460 :   if (access_mode == AccessMode::kLoad &&
     354      117530 :       LookupSpecialFieldAccessor(map, name, access_info)) {
     355             :     return true;
     356             :   }
     357             : 
     358             :   MaybeHandle<JSObject> holder;
     359       95123 :   do {
     360             :     // Lookup the named property on the {map}.
     361      465527 :     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
     362      465528 :     int const number = descriptors->Search(*name, *map);
     363      232764 :     if (number != DescriptorArray::kNotFound) {
     364      118179 :       PropertyDetails const details = descriptors->GetDetails(number);
     365      118179 :       if (access_mode == AccessMode::kStore ||
     366             :           access_mode == AccessMode::kStoreInLiteral) {
     367             :         // Don't bother optimizing stores to read-only properties.
     368       15466 :         if (details.IsReadOnly()) {
     369             :           return false;
     370             :         }
     371             :         // Check for store to data property on a prototype.
     372       12207 :         if (details.kind() == kData && !holder.is_null()) {
     373             :           // Store to property not found on the receiver but on a prototype, we
     374             :           // need to transition to a new data property.
     375             :           // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
     376        2357 :           return LookupTransition(receiver_map, name, holder, access_info);
     377             :         }
     378             :       }
     379      112563 :       if (details.location() == kField) {
     380       26706 :         if (details.kind() == kData) {
     381       53412 :           int index = descriptors->GetFieldIndex(number);
     382             :           Representation details_representation = details.representation();
     383             :           FieldIndex field_index =
     384       26706 :               FieldIndex::ForPropertyIndex(*map, index, details_representation);
     385             :           Type field_type = Type::NonInternal();
     386             :           MachineRepresentation field_representation =
     387             :               MachineRepresentation::kTagged;
     388             :           MaybeHandle<Map> field_map;
     389       26705 :           if (details_representation.IsSmi()) {
     390             :             field_type = Type::SignedSmall();
     391             :             field_representation = MachineRepresentation::kTaggedSigned;
     392       19651 :           } else if (details_representation.IsDouble()) {
     393         883 :             field_type = type_cache_->kFloat64;
     394             :             field_representation = MachineRepresentation::kFloat64;
     395       18768 :           } else if (details_representation.IsHeapObject()) {
     396             :             // Extract the field type from the property details (make sure its
     397             :             // representation is TaggedPointer to reflect the heap object case).
     398             :             field_representation = MachineRepresentation::kTaggedPointer;
     399             :             Handle<FieldType> descriptors_field_type(
     400       22728 :                 descriptors->GetFieldType(number), isolate());
     401       11363 :             if (descriptors_field_type->IsNone()) {
     402             :               // Store is not safe if the field type was cleared.
     403           0 :               if (access_mode == AccessMode::kStore) return false;
     404             : 
     405             :               // The field type was cleared by the GC, so we don't know anything
     406             :               // about the contents now.
     407       11363 :             } else if (descriptors_field_type->IsClass()) {
     408             :               MapRef map_ref(broker(), map);
     409        1447 :               map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
     410        1447 :               dependencies()->DependOnFieldType(map_ref, number);
     411             :               // Remember the field map, and try to infer a useful type.
     412        2894 :               Handle<Map> map(descriptors_field_type->AsClass(), isolate());
     413        1447 :               field_type = Type::For(MapRef(broker(), map));
     414             :               field_map = MaybeHandle<Map>(map);
     415             :             }
     416             :           }
     417       80116 :           *access_info = PropertyAccessInfo::DataField(
     418             :               details.constness(), MapHandles{receiver_map}, field_index,
     419       26706 :               field_representation, field_type, field_map, holder);
     420       26706 :           return true;
     421             :         } else {
     422             :           DCHECK_EQ(kAccessor, details.kind());
     423             :           // TODO(turbofan): Add support for general accessors?
     424             :           return false;
     425             :         }
     426             : 
     427             :       } else {
     428             :         DCHECK_EQ(kDescriptor, details.location());
     429       85857 :         if (details.kind() == kData) {
     430             :           DCHECK(!FLAG_track_constant_fields);
     431      313156 :           *access_info = PropertyAccessInfo::DataConstant(
     432             :               MapHandles{receiver_map},
     433       78289 :               handle(descriptors->GetStrongValue(number), isolate()), holder);
     434       78289 :           return true;
     435             :         } else {
     436             :           DCHECK_EQ(kAccessor, details.kind());
     437        7568 :           if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) {
     438             :             DCHECK(map->is_prototype_map());
     439             :             Handle<PrototypeInfo> proto_info(
     440             :                 PrototypeInfo::cast(map->prototype_info()), isolate());
     441             :             Handle<JSModuleNamespace> module_namespace(
     442             :                 JSModuleNamespace::cast(proto_info->module_namespace()),
     443          14 :                 isolate());
     444             :             Handle<Cell> cell(
     445          14 :                 Cell::cast(module_namespace->module()->exports()->Lookup(
     446             :                     ReadOnlyRoots(isolate()), name,
     447          14 :                     Smi::ToInt(name->GetHash()))),
     448          21 :                 isolate());
     449          14 :             if (cell->value()->IsTheHole(isolate())) {
     450             :               // This module has not been fully initialized yet.
     451             :               return false;
     452             :             }
     453          21 :             *access_info = PropertyAccessInfo::ModuleExport(
     454           7 :                 MapHandles{receiver_map}, cell);
     455           7 :             return true;
     456             :           }
     457             :           Handle<Object> accessors(descriptors->GetStrongValue(number),
     458       15122 :                                    isolate());
     459       15122 :           if (!accessors->IsAccessorPair()) return false;
     460             :           Handle<Object> accessor(
     461             :               access_mode == AccessMode::kLoad
     462       12990 :                   ? Handle<AccessorPair>::cast(accessors)->getter()
     463       14341 :                   : Handle<AccessorPair>::cast(accessors)->setter(),
     464       16580 :               isolate());
     465       12546 :           if (!accessor->IsJSFunction()) {
     466        3338 :             CallOptimization optimization(isolate(), accessor);
     467        6542 :             if (!optimization.is_simple_api_call()) return false;
     468         172 :             if (optimization.IsCrossContextLazyAccessorPair(*native_context_,
     469             :                                                             *map)) {
     470             :               return false;
     471             :             }
     472             : 
     473             :             CallOptimization::HolderLookup lookup;
     474             :             holder =
     475         166 :                 optimization.LookupHolderOfExpectedType(receiver_map, &lookup);
     476         166 :             if (lookup == CallOptimization::kHolderNotFound) return false;
     477             :             DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver,
     478             :                            holder.is_null());
     479             :             DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound,
     480             :                            !holder.is_null());
     481         134 :             if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
     482             :           }
     483        3069 :           if (access_mode == AccessMode::kLoad) {
     484             :             Handle<Name> cached_property_name;
     485        2213 :             if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
     486             :                                                                accessor)
     487        4426 :                     .ToHandle(&cached_property_name)) {
     488           6 :               if (ComputePropertyAccessInfo(map, cached_property_name,
     489             :                                             access_mode, access_info)) {
     490           6 :                 return true;
     491             :               }
     492             :             }
     493             :           }
     494        9189 :           *access_info = PropertyAccessInfo::AccessorConstant(
     495        3063 :               MapHandles{receiver_map}, accessor, holder);
     496        3063 :           return true;
     497             :         }
     498             :       }
     499             :       UNREACHABLE();
     500             :     }
     501             : 
     502             :     // Don't search on the prototype chain for special indices in case of
     503             :     // integer indexed exotic objects (see ES6 section 9.4.5).
     504      117499 :     if (map->IsJSTypedArrayMap() && name->IsString() &&
     505         938 :         IsSpecialIndex(String::cast(*name))) {
     506             :       return false;
     507             :     }
     508             : 
     509             :     // Don't search on the prototype when storing in literals
     510      114578 :     if (access_mode == AccessMode::kStoreInLiteral) {
     511         121 :       return LookupTransition(receiver_map, name, holder, access_info);
     512             :     }
     513             : 
     514             :     // Don't lookup private symbols on the prototype chain.
     515      114457 :     if (name->IsPrivate()) return false;
     516             : 
     517             :     // Walk up the prototype chain.
     518      228911 :     if (!map->prototype()->IsJSObject()) {
     519             :       // Perform the implicit ToObject for primitives here.
     520             :       // Implemented according to ES6 section 7.3.2 GetV (V, P).
     521             :       Handle<JSFunction> constructor;
     522       27893 :       if (Map::GetConstructorFunction(map, native_context())
     523       55786 :               .ToHandle(&constructor)) {
     524       17120 :         map = handle(constructor->initial_map(), isolate());
     525             :         DCHECK(map->prototype()->IsJSObject());
     526       38666 :       } else if (map->prototype()->IsNull(isolate())) {
     527             :         // Store to property not found on the receiver or any prototype, we need
     528             :         // to transition to a new data property.
     529             :         // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
     530       19326 :         if (access_mode == AccessMode::kStore) {
     531       15445 :           return LookupTransition(receiver_map, name, holder, access_info);
     532             :         }
     533             :         // The property was not found, return undefined or throw depending
     534             :         // on the language mode of the load operation.
     535             :         // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
     536       11643 :         *access_info =
     537        3881 :             PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
     538        3881 :         return true;
     539             :       } else {
     540             :         return false;
     541             :       }
     542             :     }
     543             :     Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
     544       95123 :     if (map_prototype->map()->is_deprecated()) {
     545             :       // Try to migrate the prototype object so we don't embed the deprecated
     546             :       // map into the optimized code.
     547           0 :       JSObject::TryMigrateInstance(map_prototype);
     548             :     }
     549             :     map = handle(map_prototype->map(), isolate());
     550             :     holder = map_prototype;
     551             :   } while (CanInlinePropertyAccess(map));
     552             :   return false;
     553             : }
     554             : 
     555        1191 : bool AccessInfoFactory::ComputePropertyAccessInfo(
     556             :     MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
     557        1191 :     PropertyAccessInfo* access_info) {
     558             :   ZoneVector<PropertyAccessInfo> access_infos(zone());
     559        1735 :   if (ComputePropertyAccessInfos(maps, name, access_mode, &access_infos) &&
     560         544 :       access_infos.size() == 1) {
     561         544 :     *access_info = access_infos.front();
     562         544 :     return true;
     563             :   }
     564             :   return false;
     565             : }
     566             : 
     567      144295 : bool AccessInfoFactory::ComputePropertyAccessInfos(
     568             :     MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
     569      167881 :     ZoneVector<PropertyAccessInfo>* access_infos) {
     570      427257 :   for (Handle<Map> map : maps) {
     571      311352 :     if (Map::TryUpdate(isolate(), map).ToHandle(&map)) {
     572             :       PropertyAccessInfo access_info;
     573      155662 :       if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
     574             :         return false;
     575             :       }
     576             :       // Try to merge the {access_info} with an existing one.
     577             :       bool merged = false;
     578      282297 :       for (PropertyAccessInfo& other_info : *access_infos) {
     579       12205 :         if (other_info.Merge(&access_info, access_mode, zone())) {
     580             :           merged = true;
     581             :           break;
     582             :         }
     583             :       }
     584      138653 :       if (!merged) access_infos->push_back(access_info);
     585             :     }
     586             :   }
     587      127286 :   return true;
     588             : }
     589             : 
     590             : namespace {
     591             : 
     592       14919 : Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
     593             :                                            ElementsKind that_kind) {
     594       14919 :   if (IsHoleyElementsKind(this_kind)) {
     595             :     that_kind = GetHoleyElementsKind(that_kind);
     596       12016 :   } else if (IsHoleyElementsKind(that_kind)) {
     597             :     this_kind = GetHoleyElementsKind(this_kind);
     598             :   }
     599       14919 :   if (this_kind == that_kind) return Just(this_kind);
     600         685 :   if (IsDoubleElementsKind(that_kind) == IsDoubleElementsKind(this_kind)) {
     601         632 :     if (IsMoreGeneralElementsKindTransition(that_kind, this_kind)) {
     602             :       return Just(this_kind);
     603             :     }
     604         107 :     if (IsMoreGeneralElementsKindTransition(this_kind, that_kind)) {
     605             :       return Just(that_kind);
     606             :     }
     607             :   }
     608             :   return Nothing<ElementsKind>();
     609             : }
     610             : 
     611             : }  // namespace
     612             : 
     613       14473 : bool AccessInfoFactory::ConsolidateElementLoad(MapHandles const& maps,
     614             :                                                ElementAccessInfo* access_info) {
     615       14473 :   if (maps.empty()) return false;
     616             :   InstanceType instance_type = maps.front()->instance_type();
     617             :   ElementsKind elements_kind = maps.front()->elements_kind();
     618       43705 :   for (Handle<Map> map : maps) {
     619       31050 :     if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) {
     620             :       return false;
     621             :     }
     622       29838 :     if (!GeneralizeElementsKind(elements_kind, map->elements_kind())
     623       29838 :              .To(&elements_kind)) {
     624             :       return false;
     625             :     }
     626             :   }
     627       13249 :   *access_info = ElementAccessInfo(maps, elements_kind);
     628       13249 :   return true;
     629             : }
     630             : 
     631      117530 : bool AccessInfoFactory::LookupSpecialFieldAccessor(
     632      109194 :     Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
     633             :   // Check for String::length field accessor.
     634      117530 :   if (map->IsStringMap()) {
     635        8336 :     if (Name::Equals(isolate(), name, factory()->length_string())) {
     636        8156 :       *access_info = PropertyAccessInfo::StringLength(MapHandles{map});
     637        2039 :       return true;
     638             :     }
     639             :     return false;
     640             :   }
     641             :   // Check for special JSObject field accessors.
     642             :   FieldIndex field_index;
     643      109194 :   if (Accessors::IsJSObjectFieldAccessor(isolate(), map, name, &field_index)) {
     644             :     Type field_type = Type::NonInternal();
     645             :     MachineRepresentation field_representation = MachineRepresentation::kTagged;
     646        8512 :     if (map->IsJSArrayMap()) {
     647             :       DCHECK(Name::Equals(isolate(), factory()->length_string(), name));
     648             :       // The JSArray::length property is a smi in the range
     649             :       // [0, FixedDoubleArray::kMaxLength] in case of fast double
     650             :       // elements, a smi in the range [0, FixedArray::kMaxLength]
     651             :       // in case of other fast elements, and [0, kMaxUInt32] in
     652             :       // case of other arrays.
     653        8512 :       if (IsDoubleElementsKind(map->elements_kind())) {
     654         303 :         field_type = type_cache_->kFixedDoubleArrayLengthType;
     655             :         field_representation = MachineRepresentation::kTaggedSigned;
     656        8209 :       } else if (IsFastElementsKind(map->elements_kind())) {
     657        7968 :         field_type = type_cache_->kFixedArrayLengthType;
     658             :         field_representation = MachineRepresentation::kTaggedSigned;
     659             :       } else {
     660         241 :         field_type = type_cache_->kJSArrayLengthType;
     661             :       }
     662             :     }
     663             :     // Special fields are always mutable.
     664       25536 :     *access_info = PropertyAccessInfo::DataField(
     665             :         PropertyConstness::kMutable, MapHandles{map}, field_index,
     666        8512 :         field_representation, field_type);
     667             :     return true;
     668             :   }
     669             :   return false;
     670             : }
     671             : 
     672             : 
     673       17923 : bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
     674             :                                          MaybeHandle<JSObject> holder,
     675       72863 :                                          PropertyAccessInfo* access_info) {
     676             :   // Check if the {map} has a data transition with the given {name}.
     677             :   Map transition =
     678       17923 :       TransitionsAccessor(isolate(), map).SearchTransition(*name, kData, NONE);
     679       17923 :   if (transition.is_null()) return false;
     680             : 
     681             :   Handle<Map> transition_map(transition, isolate());
     682       17890 :   int const number = transition_map->LastAdded();
     683             :   PropertyDetails const details =
     684       17890 :       transition_map->instance_descriptors()->GetDetails(number);
     685             :   // Don't bother optimizing stores to read-only properties.
     686       17890 :   if (details.IsReadOnly()) return false;
     687             :   // TODO(bmeurer): Handle transition to data constant?
     688       17890 :   if (details.location() != kField) return false;
     689             :   int const index = details.field_index();
     690             :   Representation details_representation = details.representation();
     691             :   FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index,
     692       17873 :                                                         details_representation);
     693             :   Type field_type = Type::NonInternal();
     694             :   MaybeHandle<Map> field_map;
     695             :   MachineRepresentation field_representation = MachineRepresentation::kTagged;
     696       17873 :   if (details_representation.IsSmi()) {
     697             :     field_type = Type::SignedSmall();
     698             :     field_representation = MachineRepresentation::kTaggedSigned;
     699        3443 :   } else if (details_representation.IsDouble()) {
     700         175 :     field_type = type_cache_->kFloat64;
     701             :     field_representation = MachineRepresentation::kFloat64;
     702        3268 :   } else if (details_representation.IsHeapObject()) {
     703             :     // Extract the field type from the property details (make sure its
     704             :     // representation is TaggedPointer to reflect the heap object case).
     705             :     field_representation = MachineRepresentation::kTaggedPointer;
     706             :     Handle<FieldType> descriptors_field_type(
     707        1672 :         transition_map->instance_descriptors()->GetFieldType(number),
     708        1672 :         isolate());
     709         836 :     if (descriptors_field_type->IsNone()) {
     710             :       // Store is not safe if the field type was cleared.
     711             :       return false;
     712         836 :     } else if (descriptors_field_type->IsClass()) {
     713             :       MapRef transition_map_ref(broker(), transition_map);
     714             :       transition_map_ref
     715         117 :           .SerializeOwnDescriptors();  // TODO(neis): Remove later.
     716         117 :       dependencies()->DependOnFieldType(transition_map_ref, number);
     717             :       // Remember the field map, and try to infer a useful type.
     718         234 :       Handle<Map> map(descriptors_field_type->AsClass(), isolate());
     719         117 :       field_type = Type::For(MapRef(broker(), map));
     720             :       field_map = MaybeHandle<Map>(map);
     721             :     }
     722             :   }
     723       17873 :   dependencies()->DependOnTransition(MapRef(broker(), transition_map));
     724             :   // Transitioning stores are never stores to constant fields.
     725       53619 :   *access_info = PropertyAccessInfo::DataField(
     726             :       PropertyConstness::kMutable, MapHandles{map}, field_index,
     727       17873 :       field_representation, field_type, field_map, holder, transition_map);
     728       17873 :   return true;
     729             : }
     730             : 
     731             : 
     732        8336 : Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
     733             : 
     734             : }  // namespace compiler
     735             : }  // namespace internal
     736      183867 : }  // namespace v8

Generated by: LCOV version 1.10