LCOV - code coverage report
Current view: top level - src/compiler - access-info.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 203 237 85.7 %
Date: 2017-10-20 Functions: 13 26 50.0 %

          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       44246 : bool CanInlineElementAccess(Handle<Map> map) {
      23       44246 :   if (!map->IsJSObjectMap()) return false;
      24       43571 :   if (map->is_access_check_needed()) return false;
      25       43571 :   if (map->has_indexed_interceptor()) return false;
      26             :   ElementsKind const elements_kind = map->elements_kind();
      27       43561 :   if (IsFastElementsKind(elements_kind)) return true;
      28       14171 :   if (IsFixedTypedArrayElementsKind(elements_kind)) return true;
      29         648 :   return false;
      30             : }
      31             : 
      32             : 
      33      212118 : 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      212118 :   if (map->IsBooleanMap()) return true;
      39      211849 :   if (map->instance_type() < LAST_PRIMITIVE_TYPE) return true;
      40      412691 :   return map->IsJSObjectMap() && !map->is_dictionary_map() &&
      41      412629 :          !map->has_named_interceptor() &&
      42             :          // TODO(verwaest): Whitelist contexts to which we have access.
      43      207111 :          !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             : }
      60             : 
      61           0 : ElementAccessInfo::ElementAccessInfo() {}
      62             : 
      63           0 : ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps,
      64             :                                      ElementsKind elements_kind)
      65       27376 :     : elements_kind_(elements_kind), receiver_maps_(receiver_maps) {}
      66             : 
      67             : // static
      68           0 : PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps,
      69             :                                                 MaybeHandle<JSObject> holder) {
      70           0 :   return PropertyAccessInfo(holder, receiver_maps);
      71             : }
      72             : 
      73             : // static
      74           0 : PropertyAccessInfo PropertyAccessInfo::DataConstant(
      75             :     MapHandles const& receiver_maps, Handle<Object> constant,
      76             :     MaybeHandle<JSObject> holder) {
      77           0 :   return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
      78             : }
      79             : 
      80             : // static
      81           0 : PropertyAccessInfo PropertyAccessInfo::DataField(
      82             :     PropertyConstness constness, MapHandles const& receiver_maps,
      83             :     FieldIndex field_index, MachineRepresentation field_representation,
      84             :     Type* field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
      85             :     MaybeHandle<Map> transition_map) {
      86       28613 :   Kind kind = constness == kConst ? kDataConstantField : kDataField;
      87             :   return PropertyAccessInfo(kind, holder, transition_map, field_index,
      88             :                             field_representation, field_type, field_map,
      89           0 :                             receiver_maps);
      90             : }
      91             : 
      92             : // static
      93           0 : PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
      94             :     MapHandles const& receiver_maps, Handle<Object> constant,
      95             :     MaybeHandle<JSObject> holder) {
      96           0 :   return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
      97             : }
      98             : 
      99             : // static
     100           0 : PropertyAccessInfo PropertyAccessInfo::ModuleExport(
     101             :     MapHandles const& receiver_maps, Handle<Cell> cell) {
     102             :   return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell,
     103           0 :                             receiver_maps);
     104             : }
     105             : 
     106        2049 : PropertyAccessInfo::PropertyAccessInfo()
     107             :     : kind_(kInvalid),
     108             :       field_representation_(MachineRepresentation::kNone),
     109      262799 :       field_type_(Type::None()) {}
     110             : 
     111           0 : PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
     112             :                                        MapHandles const& receiver_maps)
     113             :     : kind_(kNotFound),
     114             :       receiver_maps_(receiver_maps),
     115             :       holder_(holder),
     116             :       field_representation_(MachineRepresentation::kNone),
     117        7221 :       field_type_(Type::None()) {}
     118             : 
     119           0 : PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
     120             :                                        Handle<Object> constant,
     121             :                                        MapHandles const& receiver_maps)
     122             :     : kind_(kind),
     123             :       receiver_maps_(receiver_maps),
     124             :       constant_(constant),
     125             :       holder_(holder),
     126             :       field_representation_(MachineRepresentation::kNone),
     127      195237 :       field_type_(Type::Any()) {}
     128             : 
     129           0 : PropertyAccessInfo::PropertyAccessInfo(
     130             :     Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
     131             :     FieldIndex field_index, MachineRepresentation field_representation,
     132             :     Type* field_type, MaybeHandle<Map> field_map,
     133             :     MapHandles const& receiver_maps)
     134             :     : kind_(kind),
     135             :       receiver_maps_(receiver_maps),
     136             :       transition_map_(transition_map),
     137             :       holder_(holder),
     138             :       field_index_(field_index),
     139             :       field_representation_(field_representation),
     140             :       field_type_(field_type),
     141      112692 :       field_map_(field_map) {}
     142             : 
     143       16743 : bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
     144             :                                AccessMode access_mode, Zone* zone) {
     145       16743 :   if (this->kind_ != that->kind_) return false;
     146       16488 :   if (this->holder_.address() != that->holder_.address()) return false;
     147             : 
     148       12387 :   switch (this->kind_) {
     149             :     case kInvalid:
     150             :       break;
     151             : 
     152             :     case kDataField:
     153             :     case kDataConstantField: {
     154             :       // Check if we actually access the same field (we use the
     155             :       // GetFieldAccessStubKey method here just like the ICs do
     156             :       // since that way we only compare the relevant bits of the
     157             :       // field indices).
     158       11267 :       if (this->field_index_.GetFieldAccessStubKey() ==
     159             :           that->field_index_.GetFieldAccessStubKey()) {
     160       10343 :         switch (access_mode) {
     161             :           case AccessMode::kLoad: {
     162        4396 :             if (this->field_representation_ != that->field_representation_) {
     163        1004 :               if (!IsAnyTagged(this->field_representation_) ||
     164             :                   !IsAnyTagged(that->field_representation_)) {
     165             :                 return false;
     166             :               }
     167         502 :               this->field_representation_ = MachineRepresentation::kTagged;
     168             :             }
     169        4396 :             if (this->field_map_.address() != that->field_map_.address()) {
     170         495 :               this->field_map_ = MaybeHandle<Map>();
     171             :             }
     172             :             break;
     173             :           }
     174             :           case AccessMode::kStore:
     175             :           case AccessMode::kStoreInLiteral: {
     176             :             // For stores, the field map and field representation information
     177             :             // must match exactly, otherwise we cannot merge the stores. We
     178             :             // also need to make sure that in case of transitioning stores,
     179             :             // the transition targets match.
     180       11894 :             if (this->field_map_.address() != that->field_map_.address() ||
     181       11894 :                 this->field_representation_ != that->field_representation_ ||
     182             :                 this->transition_map_.address() !=
     183             :                     that->transition_map_.address()) {
     184             :               return false;
     185             :             }
     186             :             break;
     187             :           }
     188             :         }
     189             :         // Merge the field type.
     190             :         this->field_type_ =
     191        8256 :             Type::Union(this->field_type_, that->field_type_, zone);
     192             :         // Merge the receiver maps.
     193             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     194             :                                     that->receiver_maps_.begin(),
     195       17422 :                                     that->receiver_maps_.end());
     196        8256 :         return true;
     197             :       }
     198             :       return false;
     199             :     }
     200             : 
     201             :     case kDataConstant:
     202             :     case kAccessorConstant: {
     203             :       // Check if we actually access the same constant.
     204        1108 :       if (this->constant_.address() == that->constant_.address()) {
     205             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     206             :                                     that->receiver_maps_.begin(),
     207         898 :                                     that->receiver_maps_.end());
     208         898 :         return true;
     209             :       }
     210             :       return false;
     211             :     }
     212             : 
     213             :     case kNotFound: {
     214             :       this->receiver_maps_.insert(this->receiver_maps_.end(),
     215             :                                   that->receiver_maps_.begin(),
     216          12 :                                   that->receiver_maps_.end());
     217          12 :       return true;
     218             :     }
     219             :     case kModuleExport: {
     220             :       return false;
     221             :     }
     222             :   }
     223             : 
     224           0 :   UNREACHABLE();
     225             : }
     226             : 
     227           0 : Handle<Cell> PropertyAccessInfo::export_cell() const {
     228             :   DCHECK_EQ(kModuleExport, kind_);
     229           0 :   return Handle<Cell>::cast(constant_);
     230             : }
     231             : 
     232      140299 : AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
     233             :                                      Handle<Context> native_context, Zone* zone)
     234             :     : dependencies_(dependencies),
     235             :       native_context_(native_context),
     236             :       isolate_(native_context->GetIsolate()),
     237      140299 :       type_cache_(TypeCache::Get()),
     238      420897 :       zone_(zone) {
     239             :   DCHECK(native_context->IsNativeContext());
     240      140299 : }
     241             : 
     242             : 
     243       12671 : bool AccessInfoFactory::ComputeElementAccessInfo(
     244             :     Handle<Map> map, AccessMode access_mode, ElementAccessInfo* access_info) {
     245             :   // Check if it is safe to inline element access for the {map}.
     246       12671 :   if (!CanInlineElementAccess(map)) return false;
     247             :   ElementsKind const elements_kind = map->elements_kind();
     248       36567 :   *access_info = ElementAccessInfo(MapHandles{map}, elements_kind);
     249       12189 :   return true;
     250             : }
     251             : 
     252       26257 : bool AccessInfoFactory::ComputeElementAccessInfos(
     253       33210 :     MapHandles const& maps, AccessMode access_mode,
     254             :     ZoneVector<ElementAccessInfo>* access_infos) {
     255       26257 :   if (access_mode == AccessMode::kLoad) {
     256             :     // For polymorphic loads of similar elements kinds (i.e. all tagged or all
     257             :     // double), always use the "worst case" code without a transition.  This is
     258             :     // much faster than transitioning the elements to the worst case, trading a
     259             :     // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
     260             :     ElementAccessInfo access_info;
     261       16066 :     if (ConsolidateElementLoad(maps, &access_info)) {
     262       15187 :       access_infos->push_back(access_info);
     263       15187 :       return true;
     264         879 :     }
     265             :   }
     266             : 
     267             :   // Collect possible transition targets.
     268             :   MapHandles possible_transition_targets;
     269       11070 :   possible_transition_targets.reserve(maps.size());
     270       35583 :   for (Handle<Map> map : maps) {
     271       26886 :     if (Map::TryUpdate(map).ToHandle(&map)) {
     272       39830 :       if (CanInlineElementAccess(map) &&
     273       21702 :           IsFastElementsKind(map->elements_kind()) &&
     274             :           GetInitialFastElementsKind() != map->elements_kind()) {
     275        6551 :         possible_transition_targets.push_back(map);
     276             :       }
     277             :     }
     278             :   }
     279             : 
     280             :   // Separate the actual receiver maps and the possible transition sources.
     281             :   MapHandles receiver_maps;
     282       11070 :   receiver_maps.reserve(maps.size());
     283       11070 :   MapTransitionList transitions(maps.size());
     284       35583 :   for (Handle<Map> map : maps) {
     285       26886 :     if (Map::TryUpdate(map).ToHandle(&map)) {
     286             :       // Don't generate elements kind transitions from stable maps.
     287             :       Map* transition_target = map->is_stable()
     288             :                                    ? nullptr
     289             :                                    : map->FindElementsKindTransitionedMap(
     290       13443 :                                          possible_transition_targets);
     291       13443 :       if (transition_target == nullptr) {
     292       12808 :         receiver_maps.push_back(map);
     293             :       } else {
     294        1270 :         transitions.push_back(std::make_pair(map, handle(transition_target)));
     295             :       }
     296             :     }
     297             :   }
     298             : 
     299       34329 :   for (Handle<Map> receiver_map : receiver_maps) {
     300             :     // Compute the element access information.
     301             :     ElementAccessInfo access_info;
     302       12671 :     if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
     303         482 :       return false;
     304             :     }
     305             : 
     306             :     // Collect the possible transitions for the {receiver_map}.
     307       41453 :     for (auto transition : transitions) {
     308       17075 :       if (transition.second.is_identical_to(receiver_map)) {
     309         619 :         access_info.transitions().push_back(transition);
     310             :       }
     311             :     }
     312             : 
     313             :     // Schedule the access information.
     314       12189 :     access_infos->push_back(access_info);
     315       12189 :   }
     316       10588 :   return true;
     317             : }
     318             : 
     319             : 
     320      130383 : bool AccessInfoFactory::ComputePropertyAccessInfo(
     321             :     Handle<Map> map, Handle<Name> name, AccessMode access_mode,
     322      812035 :     PropertyAccessInfo* access_info) {
     323             :   // Check if it is safe to inline property access for the {map}.
     324      130383 :   if (!CanInlinePropertyAccess(map)) return false;
     325             : 
     326             :   // Compute the receiver type.
     327             :   Handle<Map> receiver_map = map;
     328             : 
     329             :   // Property lookups require the name to be internalized.
     330      129778 :   name = isolate()->factory()->InternalizeName(name);
     331             : 
     332             :   // We support fast inline cases for certain JSObject getters.
     333      222610 :   if (access_mode == AccessMode::kLoad &&
     334       92832 :       LookupSpecialFieldAccessor(map, name, access_info)) {
     335             :     return true;
     336             :   }
     337             : 
     338             :   MaybeHandle<JSObject> holder;
     339       81735 :   do {
     340             :     // Lookup the named property on the {map}.
     341             :     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
     342             :     int const number = descriptors->SearchWithCache(isolate(), *name, *map);
     343      203206 :     if (number != DescriptorArray::kNotFound) {
     344      100023 :       PropertyDetails const details = descriptors->GetDetails(number);
     345      100023 :       if (access_mode == AccessMode::kStore ||
     346             :           access_mode == AccessMode::kStoreInLiteral) {
     347             :         // Don't bother optimizing stores to read-only properties.
     348       16983 :         if (details.IsReadOnly()) {
     349             :           return false;
     350             :         }
     351             :         // Check for store to data property on a prototype.
     352       14971 :         if (details.kind() == kData && !holder.is_null()) {
     353             :           // Store to property not found on the receiver but on a prototype, we
     354             :           // need to transition to a new data property.
     355             :           // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
     356        1464 :           return LookupTransition(receiver_map, name, holder, access_info);
     357             :         }
     358             :       }
     359       96547 :       if (details.location() == kField) {
     360       28613 :         if (details.kind() == kData) {
     361             :           int index = descriptors->GetFieldIndex(number);
     362             :           Representation details_representation = details.representation();
     363             :           FieldIndex field_index = FieldIndex::ForPropertyIndex(
     364       57226 :               *map, index, details_representation.IsDouble());
     365             :           Type* field_type = Type::NonInternal();
     366             :           MachineRepresentation field_representation =
     367             :               MachineRepresentation::kTagged;
     368             :           MaybeHandle<Map> field_map;
     369       28613 :           if (details_representation.IsSmi()) {
     370             :             field_type = Type::SignedSmall();
     371             :             field_representation = MachineRepresentation::kTaggedSigned;
     372       22650 :           } else if (details_representation.IsDouble()) {
     373         607 :             field_type = type_cache_.kFloat64;
     374             :             field_representation = MachineRepresentation::kFloat64;
     375       22043 :           } else if (details_representation.IsHeapObject()) {
     376             :             // Extract the field type from the property details (make sure its
     377             :             // representation is TaggedPointer to reflect the heap object case).
     378             :             field_representation = MachineRepresentation::kTaggedPointer;
     379             :             Handle<FieldType> descriptors_field_type(
     380        7734 :                 descriptors->GetFieldType(number), isolate());
     381        7734 :             if (descriptors_field_type->IsNone()) {
     382             :               // Store is not safe if the field type was cleared.
     383           0 :               if (access_mode == AccessMode::kStore) return false;
     384             : 
     385             :               // The field type was cleared by the GC, so we don't know anything
     386             :               // about the contents now.
     387        7734 :             } else if (descriptors_field_type->IsClass()) {
     388             :               // Add proper code dependencies in case of stable field map(s).
     389             :               Handle<Map> field_owner_map(map->FindFieldOwner(number),
     390        1116 :                                           isolate());
     391             :               dependencies()->AssumeFieldOwner(field_owner_map);
     392             : 
     393             :               // Remember the field map, and try to infer a useful type.
     394        1116 :               field_type = Type::For(descriptors_field_type->AsClass());
     395        1116 :               field_map = descriptors_field_type->AsClass();
     396             :             }
     397             :           }
     398       85839 :           *access_info = PropertyAccessInfo::DataField(
     399             :               details.constness(), MapHandles{receiver_map}, field_index,
     400       28613 :               field_representation, field_type, field_map, holder);
     401       28613 :           return true;
     402             :         } else {
     403             :           DCHECK_EQ(kAccessor, details.kind());
     404             :           // TODO(turbofan): Add support for general accessors?
     405             :           return false;
     406             :         }
     407             : 
     408             :       } else {
     409             :         DCHECK_EQ(kDescriptor, details.location());
     410       67934 :         if (details.kind() == kData) {
     411             :           DCHECK(!FLAG_track_constant_fields);
     412      183999 :           *access_info = PropertyAccessInfo::DataConstant(
     413             :               MapHandles{receiver_map},
     414       61333 :               handle(descriptors->GetValue(number), isolate()), holder);
     415       61333 :           return true;
     416             :         } else {
     417             :           DCHECK_EQ(kAccessor, details.kind());
     418        6601 :           if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) {
     419             :             DCHECK(map->is_prototype_map());
     420             :             Handle<PrototypeInfo> proto_info =
     421           0 :                 Map::GetOrCreatePrototypeInfo(map, isolate());
     422             :             DCHECK(proto_info->weak_cell()->IsWeakCell());
     423             :             Handle<JSModuleNamespace> module_namespace(
     424             :                 JSModuleNamespace::cast(
     425             :                     WeakCell::cast(proto_info->weak_cell())->value()),
     426             :                 isolate());
     427             :             Handle<Cell> cell(
     428             :                 Cell::cast(module_namespace->module()->exports()->Lookup(
     429           0 :                     isolate(), name, Smi::ToInt(name->GetHash()))),
     430           0 :                 isolate());
     431           0 :             if (cell->value()->IsTheHole(isolate())) {
     432             :               // This module has not been fully initialized yet.
     433             :               return false;
     434             :             }
     435           0 :             *access_info = PropertyAccessInfo::ModuleExport(
     436           0 :                 MapHandles{receiver_map}, cell);
     437           0 :             return true;
     438             :           }
     439             :           Handle<Object> accessors(descriptors->GetValue(number), isolate());
     440        6601 :           if (!accessors->IsAccessorPair()) return false;
     441             :           Handle<Object> accessor(
     442             :               access_mode == AccessMode::kLoad
     443             :                   ? Handle<AccessorPair>::cast(accessors)->getter()
     444             :                   : Handle<AccessorPair>::cast(accessors)->setter(),
     445        5921 :               isolate());
     446        5921 :           if (!accessor->IsJSFunction()) {
     447        2310 :             CallOptimization optimization(accessor);
     448        4477 :             if (!optimization.is_simple_api_call()) return false;
     449             :             CallOptimization::HolderLookup lookup;
     450             :             holder =
     451         175 :                 optimization.LookupHolderOfExpectedType(receiver_map, &lookup);
     452         175 :             if (lookup == CallOptimization::kHolderNotFound) return false;
     453             :             DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver,
     454             :                            holder.is_null());
     455             :             DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound,
     456             :                            !holder.is_null());
     457         143 :             if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
     458             :           }
     459        3754 :           if (access_mode == AccessMode::kLoad) {
     460             :             Handle<Name> cached_property_name;
     461        2875 :             if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
     462             :                                                                accessor)
     463        5750 :                     .ToHandle(&cached_property_name)) {
     464           8 :               if (ComputePropertyAccessInfo(map, cached_property_name,
     465             :                                             access_mode, access_info)) {
     466           8 :                 return true;
     467             :               }
     468             :             }
     469             :           }
     470       11238 :           *access_info = PropertyAccessInfo::AccessorConstant(
     471        3746 :               MapHandles{receiver_map}, accessor, holder);
     472        3746 :           return true;
     473             :         }
     474             :       }
     475             :       UNREACHABLE();
     476             :     }
     477             : 
     478             :     // Don't search on the prototype chain for special indices in case of
     479             :     // integer indexed exotic objects (see ES6 section 9.4.5).
     480      104936 :     if (map->IsJSTypedArrayMap() && name->IsString() &&
     481         855 :         IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
     482             :       return false;
     483             :     }
     484             : 
     485             :     // Don't search on the prototype when storing in literals
     486      103176 :     if (access_mode == AccessMode::kStoreInLiteral) {
     487         129 :       return LookupTransition(receiver_map, name, holder, access_info);
     488             :     }
     489             : 
     490             :     // Don't lookup private symbols on the prototype chain.
     491      103047 :     if (name->IsPrivate()) return false;
     492             : 
     493             :     // Walk up the prototype chain.
     494      103044 :     if (!map->prototype()->IsJSObject()) {
     495             :       // Perform the implicit ToObject for primitives here.
     496             :       // Implemented according to ES6 section 7.3.2 GetV (V, P).
     497             :       Handle<JSFunction> constructor;
     498       24824 :       if (Map::GetConstructorFunction(map, native_context())
     499       49648 :               .ToHandle(&constructor)) {
     500             :         map = handle(constructor->initial_map(), isolate());
     501             :         DCHECK(map->prototype()->IsJSObject());
     502       21309 :       } else if (map->prototype()->IsNull(isolate())) {
     503             :         // Store to property not found on the receiver or any prototype, we need
     504             :         // to transition to a new data property.
     505             :         // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
     506       21302 :         if (access_mode == AccessMode::kStore) {
     507       18895 :           return LookupTransition(receiver_map, name, holder, access_info);
     508             :         }
     509             :         // The property was not found, return undefined or throw depending
     510             :         // on the language mode of the load operation.
     511             :         // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
     512        7221 :         *access_info =
     513        2407 :             PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
     514        2407 :         return true;
     515             :       } else {
     516             :         return false;
     517             :       }
     518             :     }
     519             :     Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
     520       81735 :     if (map_prototype->map()->is_deprecated()) {
     521             :       // Try to migrate the prototype object so we don't embed the deprecated
     522             :       // map into the optimized code.
     523           0 :       JSObject::TryMigrateInstance(map_prototype);
     524             :     }
     525             :     map = handle(map_prototype->map(), isolate());
     526             :     holder = map_prototype;
     527             :   } while (CanInlinePropertyAccess(map));
     528             :   return false;
     529             : }
     530             : 
     531      111993 : bool AccessInfoFactory::ComputePropertyAccessInfos(
     532             :     MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
     533       16743 :     ZoneVector<PropertyAccessInfo>* access_infos) {
     534      345986 :   for (Handle<Map> map : maps) {
     535      256652 :     if (Map::TryUpdate(map).ToHandle(&map)) {
     536             :       PropertyAccessInfo access_info;
     537      128326 :       if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
     538             :         return false;
     539             :       }
     540             :       // Try to merge the {access_info} with an existing one.
     541             :       bool merged = false;
     542      251577 :       for (PropertyAccessInfo& other_info : *access_infos) {
     543       16743 :         if (other_info.Merge(&access_info, access_mode, zone())) {
     544             :           merged = true;
     545             :           break;
     546             :         }
     547             :       }
     548      122000 :       if (!merged) access_infos->push_back(access_info);
     549             :     }
     550             :   }
     551      105667 :   return true;
     552             : }
     553             : 
     554             : namespace {
     555             : 
     556       17543 : Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
     557             :                                            ElementsKind that_kind) {
     558       17543 :   if (IsHoleyOrDictionaryElementsKind(this_kind)) {
     559             :     that_kind = GetHoleyElementsKind(that_kind);
     560       13474 :   } else if (IsHoleyOrDictionaryElementsKind(that_kind)) {
     561             :     this_kind = GetHoleyElementsKind(this_kind);
     562             :   }
     563       17543 :   if (this_kind == that_kind) return Just(this_kind);
     564        1500 :   if (IsDoubleElementsKind(that_kind) == IsDoubleElementsKind(this_kind)) {
     565        1308 :     if (IsMoreGeneralElementsKindTransition(that_kind, this_kind)) {
     566             :       return Just(this_kind);
     567             :     }
     568          98 :     if (IsMoreGeneralElementsKindTransition(this_kind, that_kind)) {
     569             :       return Just(that_kind);
     570             :     }
     571             :   }
     572             :   return Nothing<ElementsKind>();
     573             : }
     574             : 
     575             : }  // namespace
     576             : 
     577       16066 : bool AccessInfoFactory::ConsolidateElementLoad(MapHandles const& maps,
     578             :                                                ElementAccessInfo* access_info) {
     579       16066 :   if (maps.empty()) return false;
     580             :   InstanceType instance_type = maps.front()->instance_type();
     581             :   ElementsKind elements_kind = maps.front()->elements_kind();
     582       49385 :   for (Handle<Map> map : maps) {
     583       35912 :     if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) {
     584             :       return false;
     585             :     }
     586       17543 :     if (!GeneralizeElementsKind(elements_kind, map->elements_kind())
     587       35086 :              .To(&elements_kind)) {
     588             :       return false;
     589             :     }
     590             :   }
     591       15187 :   *access_info = ElementAccessInfo(maps, elements_kind);
     592       15187 :   return true;
     593             : }
     594             : 
     595       92832 : bool AccessInfoFactory::LookupSpecialFieldAccessor(
     596             :     Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
     597             :   // Check for special JSObject field accessors.
     598             :   int offset;
     599       92832 :   if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
     600        7299 :     FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
     601             :     Type* field_type = Type::NonInternal();
     602             :     MachineRepresentation field_representation = MachineRepresentation::kTagged;
     603        7299 :     if (map->IsStringMap()) {
     604             :       DCHECK(Name::Equals(factory()->length_string(), name));
     605             :       // The String::length property is always a smi in the range
     606             :       // [0, String::kMaxLength].
     607        1492 :       field_type = type_cache_.kStringLengthType;
     608             :       field_representation = MachineRepresentation::kTaggedSigned;
     609        5807 :     } else if (map->IsJSArrayMap()) {
     610             :       DCHECK(Name::Equals(factory()->length_string(), name));
     611             :       // The JSArray::length property is a smi in the range
     612             :       // [0, FixedDoubleArray::kMaxLength] in case of fast double
     613             :       // elements, a smi in the range [0, FixedArray::kMaxLength]
     614             :       // in case of other fast elements, and [0, kMaxUInt32] in
     615             :       // case of other arrays.
     616        5807 :       if (IsDoubleElementsKind(map->elements_kind())) {
     617         327 :         field_type = type_cache_.kFixedDoubleArrayLengthType;
     618             :         field_representation = MachineRepresentation::kTaggedSigned;
     619        5480 :       } else if (IsFastElementsKind(map->elements_kind())) {
     620        5231 :         field_type = type_cache_.kFixedArrayLengthType;
     621             :         field_representation = MachineRepresentation::kTaggedSigned;
     622             :       } else {
     623         249 :         field_type = type_cache_.kJSArrayLengthType;
     624             :       }
     625             :     }
     626             :     // Special fields are always mutable.
     627       21897 :     *access_info =
     628             :         PropertyAccessInfo::DataField(kMutable, MapHandles{map}, field_index,
     629        7299 :                                       field_representation, field_type);
     630             :     return true;
     631             :   }
     632             :   return false;
     633             : }
     634             : 
     635             : 
     636       20488 : bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
     637             :                                          MaybeHandle<JSObject> holder,
     638       21674 :                                          PropertyAccessInfo* access_info) {
     639             :   // Check if the {map} has a data transition with the given {name}.
     640             :   Map* transition =
     641       20488 :       TransitionsAccessor(map).SearchTransition(*name, kData, NONE);
     642       20488 :   if (transition == nullptr) return false;
     643             : 
     644             :   Handle<Map> transition_map(transition);
     645             :   int const number = transition_map->LastAdded();
     646             :   PropertyDetails const details =
     647       20454 :       transition_map->instance_descriptors()->GetDetails(number);
     648             :   // Don't bother optimizing stores to read-only properties.
     649       20454 :   if (details.IsReadOnly()) return false;
     650             :   // TODO(bmeurer): Handle transition to data constant?
     651       20454 :   if (details.location() != kField) return false;
     652             :   int const index = details.field_index();
     653             :   Representation details_representation = details.representation();
     654             :   FieldIndex field_index = FieldIndex::ForPropertyIndex(
     655       40868 :       *transition_map, index, details_representation.IsDouble());
     656             :   Type* field_type = Type::NonInternal();
     657             :   MaybeHandle<Map> field_map;
     658             :   MachineRepresentation field_representation = MachineRepresentation::kTagged;
     659       20434 :   if (details_representation.IsSmi()) {
     660             :     field_type = Type::SignedSmall();
     661             :     field_representation = MachineRepresentation::kTaggedSigned;
     662       10243 :   } else if (details_representation.IsDouble()) {
     663         143 :     field_type = type_cache_.kFloat64;
     664             :     field_representation = MachineRepresentation::kFloat64;
     665       10100 :   } else if (details_representation.IsHeapObject()) {
     666             :     // Extract the field type from the property details (make sure its
     667             :     // representation is TaggedPointer to reflect the heap object case).
     668             :     field_representation = MachineRepresentation::kTaggedPointer;
     669             :     Handle<FieldType> descriptors_field_type(
     670             :         transition_map->instance_descriptors()->GetFieldType(number),
     671        1048 :         isolate());
     672        1048 :     if (descriptors_field_type->IsNone()) {
     673             :       // Store is not safe if the field type was cleared.
     674             :       return false;
     675        1048 :     } else if (descriptors_field_type->IsClass()) {
     676             :       // Add proper code dependencies in case of stable field map(s).
     677             :       Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
     678          96 :                                   isolate());
     679             :       dependencies()->AssumeFieldOwner(field_owner_map);
     680             : 
     681             :       // Remember the field map, and try to infer a useful type.
     682          96 :       field_type = Type::For(descriptors_field_type->AsClass());
     683          96 :       field_map = descriptors_field_type->AsClass();
     684             :     }
     685             :   }
     686       20434 :   dependencies()->AssumeMapNotDeprecated(transition_map);
     687             :   // Transitioning stores are never stores to constant fields.
     688       61302 :   *access_info = PropertyAccessInfo::DataField(
     689             :       kMutable, MapHandles{map}, field_index, field_representation, field_type,
     690       20434 :       field_map, holder, transition_map);
     691       20434 :   return true;
     692             : }
     693             : 
     694             : 
     695           0 : Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
     696             : 
     697             : }  // namespace compiler
     698             : }  // namespace internal
     699             : }  // namespace v8

Generated by: LCOV version 1.10