LCOV - code coverage report
Current view: top level - src/compiler - access-info.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 246 272 90.4 %
Date: 2019-02-19 Functions: 21 32 65.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       37805 : bool CanInlineElementAccess(Handle<Map> map) {
      28       37805 :   if (!map->IsJSObjectMap()) return false;
      29       36222 :   if (map->is_access_check_needed()) return false;
      30       36222 :   if (map->has_indexed_interceptor()) return false;
      31             :   ElementsKind const elements_kind = map->elements_kind();
      32       36214 :   if (IsFastElementsKind(elements_kind)) return true;
      33       12066 :   if (IsFixedTypedArrayElementsKind(elements_kind) &&
      34       12066 :       elements_kind != BIGUINT64_ELEMENTS &&
      35             :       elements_kind != BIGINT64_ELEMENTS) {
      36             :     return true;
      37             :   }
      38        1606 :   return false;
      39             : }
      40             : 
      41             : 
      42      258695 : 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      258695 :   if (map->IsBooleanMap()) return true;
      48      258171 :   if (map->instance_type() < LAST_PRIMITIVE_TYPE) return true;
      49      737407 :   return map->IsJSObjectMap() && !map->is_dictionary_map() &&
      50      489937 :          !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       22699 : ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps,
      73             :                                      ElementsKind elements_kind)
      74       22699 :     : elements_kind_(elements_kind), receiver_maps_(receiver_maps) {
      75       22699 :   CHECK(!receiver_maps.empty());
      76       22699 : }
      77             : 
      78             : // static
      79           0 : PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps,
      80             :                                                 MaybeHandle<JSObject> holder) {
      81           0 :   return PropertyAccessInfo(kNotFound, holder, receiver_maps);
      82             : }
      83             : 
      84             : // static
      85           0 : PropertyAccessInfo PropertyAccessInfo::DataConstant(
      86             :     MapHandles const& receiver_maps, Handle<Object> constant,
      87             :     MaybeHandle<JSObject> holder) {
      88           0 :   return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
      89             : }
      90             : 
      91             : // static
      92           0 : PropertyAccessInfo PropertyAccessInfo::DataField(
      93             :     PropertyConstness constness, MapHandles const& receiver_maps,
      94             :     FieldIndex field_index, MachineRepresentation field_representation,
      95             :     Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
      96             :     MaybeHandle<Map> transition_map) {
      97             :   Kind kind =
      98      103570 :       constness == PropertyConstness::kConst ? kDataConstantField : kDataField;
      99             :   return PropertyAccessInfo(kind, holder, transition_map, field_index,
     100             :                             field_representation, field_type, field_map,
     101           0 :                             receiver_maps);
     102             : }
     103             : 
     104             : // static
     105           0 : PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
     106             :     MapHandles const& receiver_maps, Handle<Object> constant,
     107             :     MaybeHandle<JSObject> holder) {
     108           0 :   return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
     109             : }
     110             : 
     111             : // static
     112           0 : PropertyAccessInfo PropertyAccessInfo::ModuleExport(
     113             :     MapHandles const& receiver_maps, Handle<Cell> cell) {
     114             :   return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell,
     115           0 :                             receiver_maps);
     116             : }
     117             : 
     118             : // static
     119           0 : PropertyAccessInfo PropertyAccessInfo::StringLength(
     120             :     MapHandles const& receiver_maps) {
     121             :   return PropertyAccessInfo(kStringLength, MaybeHandle<JSObject>(),
     122           0 :                             receiver_maps);
     123             : }
     124             : 
     125        2372 : PropertyAccessInfo::PropertyAccessInfo()
     126             :     : kind_(kInvalid),
     127             :       field_representation_(MachineRepresentation::kNone),
     128      476613 :       field_type_(Type::None()) {}
     129             : 
     130           0 : PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
     131             :                                        MapHandles const& receiver_maps)
     132             :     : kind_(kind),
     133             :       receiver_maps_(receiver_maps),
     134             :       holder_(holder),
     135             :       field_representation_(MachineRepresentation::kNone),
     136       16461 :       field_type_(Type::None()) {}
     137             : 
     138           0 : PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
     139             :                                        Handle<Object> constant,
     140             :                                        MapHandles const& receiver_maps)
     141             :     : kind_(kind),
     142             :       receiver_maps_(receiver_maps),
     143             :       constant_(constant),
     144             :       holder_(holder),
     145             :       field_representation_(MachineRepresentation::kNone),
     146        6184 :       field_type_(Type::Any()) {}
     147             : 
     148           0 : PropertyAccessInfo::PropertyAccessInfo(
     149             :     Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
     150             :     FieldIndex field_index, MachineRepresentation field_representation,
     151             :     Type field_type, MaybeHandle<Map> field_map,
     152             :     MapHandles const& receiver_maps)
     153             :     : kind_(kind),
     154             :       receiver_maps_(receiver_maps),
     155             :       transition_map_(transition_map),
     156             :       holder_(holder),
     157             :       field_index_(field_index),
     158             :       field_representation_(field_representation),
     159             :       field_type_(field_type),
     160      268660 :       field_map_(field_map) {}
     161             : 
     162       14415 : bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
     163             :                                AccessMode access_mode, Zone* zone) {
     164       14415 :   if (this->kind_ != that->kind_) return false;
     165       13872 :   if (this->holder_.address() != that->holder_.address()) return false;
     166             : 
     167       12827 :   switch (this->kind_) {
     168             :     case kInvalid:
     169             :       break;
     170             : 
     171             :     case kDataField:
     172             :     case kDataConstantField: {
     173             :       // Check if we actually access the same field (we use the
     174             :       // GetFieldAccessStubKey method here just like the ICs do
     175             :       // since that way we only compare the relevant bits of the
     176             :       // field indices).
     177       12335 :       if (this->field_index_.GetFieldAccessStubKey() ==
     178             :           that->field_index_.GetFieldAccessStubKey()) {
     179       11533 :         switch (access_mode) {
     180             :           case AccessMode::kLoad: {
     181        6968 :             if (this->field_representation_ != that->field_representation_) {
     182         690 :               if (!IsAnyTagged(this->field_representation_) ||
     183             :                   !IsAnyTagged(that->field_representation_)) {
     184             :                 return false;
     185             :               }
     186         345 :               this->field_representation_ = MachineRepresentation::kTagged;
     187             :             }
     188        6968 :             if (this->field_map_.address() != that->field_map_.address()) {
     189         233 :               this->field_map_ = MaybeHandle<Map>();
     190             :             }
     191             :             break;
     192             :           }
     193             :           case AccessMode::kStore:
     194             :           case AccessMode::kStoreInLiteral: {
     195             :             // For stores, the field map and field representation information
     196             :             // must match exactly, otherwise we cannot merge the stores. We
     197             :             // also need to make sure that in case of transitioning stores,
     198             :             // the transition targets match.
     199        9082 :             if (this->field_map_.address() != that->field_map_.address() ||
     200        8974 :                 this->field_representation_ != that->field_representation_ ||
     201             :                 this->transition_map_.address() !=
     202             :                     that->transition_map_.address()) {
     203             :               return false;
     204             :             }
     205             :             break;
     206             :           }
     207             :         }
     208             :         // Merge the field type.
     209             :         this->field_type_ =
     210        7201 :             Type::Union(this->field_type_, that->field_type_, zone);
     211             :         // Merge the receiver maps.
     212             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     213             :                                     that->receiver_maps_.begin(),
     214       14887 :                                     that->receiver_maps_.end());
     215        7201 :         return true;
     216             :       }
     217             :       return false;
     218             :     }
     219             : 
     220             :     case kDataConstant:
     221             :     case kAccessorConstant: {
     222             :       // Check if we actually access the same constant.
     223         288 :       if (this->constant_.address() == that->constant_.address()) {
     224             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     225             :                                     that->receiver_maps_.begin(),
     226         281 :                                     that->receiver_maps_.end());
     227         281 :         return true;
     228             :       }
     229             :       return false;
     230             :     }
     231             : 
     232             :     case kNotFound:
     233             :     case kStringLength: {
     234             :       this->receiver_maps_.insert(this->receiver_maps_.end(),
     235             :                                   that->receiver_maps_.begin(),
     236         204 :                                   that->receiver_maps_.end());
     237         204 :       return true;
     238             :     }
     239             :     case kModuleExport: {
     240             :       return false;
     241             :     }
     242             :   }
     243             : 
     244           0 :   UNREACHABLE();
     245             : }
     246             : 
     247           7 : Handle<Cell> PropertyAccessInfo::export_cell() const {
     248             :   DCHECK_EQ(kModuleExport, kind_);
     249           7 :   return Handle<Cell>::cast(constant_);
     250             : }
     251             : 
     252      167109 : AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
     253             :                                      CompilationDependencies* dependencies,
     254             :                                      Handle<Context> native_context, Zone* zone)
     255             :     : broker_(broker),
     256             :       dependencies_(dependencies),
     257             :       native_context_(native_context),
     258             :       isolate_(native_context->GetIsolate()),
     259      167109 :       type_cache_(TypeCache::Get()),
     260      501327 :       zone_(zone) {
     261             :   DCHECK(native_context->IsNativeContext());
     262      167109 : }
     263             : 
     264       10183 : bool AccessInfoFactory::ComputeElementAccessInfo(
     265             :     Handle<Map> map, AccessMode access_mode,
     266             :     ElementAccessInfo* access_info) const {
     267             :   // Check if it is safe to inline element access for the {map}.
     268       10183 :   if (!CanInlineElementAccess(map)) return false;
     269             :   ElementsKind const elements_kind = map->elements_kind();
     270       27459 :   *access_info = ElementAccessInfo(MapHandles{map}, elements_kind);
     271        9153 :   return true;
     272             : }
     273             : 
     274             : typedef std::vector<std::pair<Handle<Map>, Handle<Map>>> TransitionList;
     275             : 
     276             : namespace {
     277       18952 : void ProcessFeedbackMaps(Isolate* isolate, MapHandles const& maps,
     278             :                          MapHandles* receiver_maps,
     279             :                          TransitionList* transitions) {
     280             :   DCHECK(receiver_maps->empty());
     281             :   DCHECK(transitions->empty());
     282             : 
     283             :   // Collect possible transition targets.
     284             :   MapHandles possible_transition_targets;
     285        9476 :   possible_transition_targets.reserve(maps.size());
     286       29995 :   for (Handle<Map> map : maps) {
     287       31866 :     if (CanInlineElementAccess(map) &&
     288       17294 :         IsFastElementsKind(map->elements_kind()) &&
     289             :         GetInitialFastElementsKind() != map->elements_kind()) {
     290        4903 :       possible_transition_targets.push_back(map);
     291             :     }
     292             :   }
     293             : 
     294             :   // Separate the actual receiver maps and the possible transition sources.
     295       29995 :   for (Handle<Map> map : maps) {
     296             :     // Don't generate elements kind transitions from stable maps.
     297       22086 :     Map transition_target = map->is_stable()
     298             :                                 ? Map()
     299             :                                 : map->FindElementsKindTransitionedMap(
     300       16954 :                                       isolate, possible_transition_targets);
     301       11043 :     if (transition_target.is_null()) {
     302       10470 :       receiver_maps->push_back(map);
     303             :     } else {
     304         573 :       transitions->emplace_back(map, handle(transition_target, isolate));
     305             :     }
     306             :   }
     307        9476 : }
     308             : }  // namespace
     309             : 
     310       23022 : bool AccessInfoFactory::ComputeElementAccessInfos(
     311             :     MapHandles const& maps, AccessMode access_mode,
     312        9476 :     ZoneVector<ElementAccessInfo>* access_infos) const {
     313       23022 :   if (access_mode == AccessMode::kLoad) {
     314             :     // For polymorphic loads of similar elements kinds (i.e. all tagged or all
     315             :     // double), always use the "worst case" code without a transition.  This is
     316             :     // much faster than transitioning the elements to the worst case, trading a
     317             :     // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
     318             :     ElementAccessInfo access_info;
     319       14779 :     if (ConsolidateElementLoad(maps, &access_info)) {
     320       13546 :       access_infos->push_back(access_info);
     321       13546 :       return true;
     322        1233 :     }
     323             :   }
     324             : 
     325             :   MapHandles receiver_maps;
     326             :   TransitionList transitions;
     327        9476 :   ProcessFeedbackMaps(isolate(), maps, &receiver_maps, &transitions);
     328             : 
     329       28105 :   for (Handle<Map> receiver_map : receiver_maps) {
     330             :     // Compute the element access information.
     331             :     ElementAccessInfo access_info;
     332       10183 :     if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
     333        1030 :       return false;
     334             :     }
     335             : 
     336             :     // Collect the possible transitions for the {receiver_map}.
     337       18931 :     for (auto transition : transitions) {
     338         625 :       if (transition.second.is_identical_to(receiver_map)) {
     339         545 :         access_info.AddTransitionSource(transition.first);
     340             :       }
     341             :     }
     342             : 
     343             :     // Schedule the access information.
     344        9153 :     access_infos->push_back(access_info);
     345        9153 :   }
     346        8446 :   return true;
     347             : }
     348             : 
     349      103570 : bool AccessInfoFactory::ComputeDataFieldAccessInfo(
     350             :     Handle<Map> receiver_map, Handle<Map> map, MaybeHandle<JSObject> holder,
     351      195812 :     int number, AccessMode access_mode, PropertyAccessInfo* access_info) const {
     352             :   DCHECK_NE(number, DescriptorArray::kNotFound);
     353      207140 :   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
     354      103570 :   PropertyDetails const details = descriptors->GetDetails(number);
     355      207140 :   int index = descriptors->GetFieldIndex(number);
     356             :   Representation details_representation = details.representation();
     357             :   FieldIndex field_index =
     358      103570 :       FieldIndex::ForPropertyIndex(*map, index, details_representation);
     359             :   Type field_type = Type::NonInternal();
     360             :   MachineRepresentation field_representation = MachineRepresentation::kTagged;
     361             :   MaybeHandle<Map> field_map;
     362      103570 :   if (details_representation.IsSmi()) {
     363             :     field_type = Type::SignedSmall();
     364             :     field_representation = MachineRepresentation::kTaggedSigned;
     365       96461 :   } else if (details_representation.IsDouble()) {
     366         897 :     field_type = type_cache_->kFloat64;
     367             :     field_representation = MachineRepresentation::kFloat64;
     368       95564 :   } else if (details_representation.IsHeapObject()) {
     369             :     // Extract the field type from the property details (make sure its
     370             :     // representation is TaggedPointer to reflect the heap object case).
     371             :     field_representation = MachineRepresentation::kTaggedPointer;
     372             :     Handle<FieldType> descriptors_field_type(descriptors->GetFieldType(number),
     373      165572 :                                              isolate());
     374       82786 :     if (descriptors_field_type->IsNone()) {
     375             :       // Store is not safe if the field type was cleared.
     376           7 :       if (access_mode == AccessMode::kStore) return false;
     377             : 
     378             :       // The field type was cleared by the GC, so we don't know anything
     379             :       // about the contents now.
     380       82779 :     } else if (descriptors_field_type->IsClass()) {
     381             :       MapRef map_ref(broker(), map);
     382        2364 :       map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
     383        2364 :       dependencies()->DependOnFieldType(map_ref, number);
     384             :       // Remember the field map, and try to infer a useful type.
     385        4728 :       Handle<Map> map(descriptors_field_type->AsClass(), isolate());
     386        2364 :       field_type = Type::For(MapRef(broker(), map));
     387             :       field_map = MaybeHandle<Map>(map);
     388             :     }
     389             :   }
     390      310710 :   *access_info = PropertyAccessInfo::DataField(
     391             :       details.constness(), MapHandles{receiver_map}, field_index,
     392      103570 :       field_representation, field_type, field_map, holder);
     393      103570 :   return true;
     394             : }
     395             : 
     396        7519 : bool AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
     397             :     Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map,
     398             :     MaybeHandle<JSObject> holder, int number, AccessMode access_mode,
     399       26938 :     PropertyAccessInfo* access_info) const {
     400             :   DCHECK_NE(number, DescriptorArray::kNotFound);
     401       15038 :   Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
     402             :   SLOW_DCHECK(number == descriptors->Search(*name, *map));
     403        7519 :   if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) {
     404             :     DCHECK(map->is_prototype_map());
     405             :     Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(map->prototype_info()),
     406             :                                      isolate());
     407             :     Handle<JSModuleNamespace> module_namespace(
     408             :         JSModuleNamespace::cast(proto_info->module_namespace()), isolate());
     409             :     Handle<Cell> cell(
     410          14 :         Cell::cast(module_namespace->module()->exports()->Lookup(
     411          14 :             ReadOnlyRoots(isolate()), name, Smi::ToInt(name->GetHash()))),
     412          21 :         isolate());
     413          14 :     if (cell->value()->IsTheHole(isolate())) {
     414             :       // This module has not been fully initialized yet.
     415             :       return false;
     416             :     }
     417          21 :     *access_info =
     418           7 :         PropertyAccessInfo::ModuleExport(MapHandles{receiver_map}, cell);
     419           7 :     return true;
     420             :   }
     421       15024 :   Handle<Object> accessors(descriptors->GetStrongValue(number), isolate());
     422       15024 :   if (!accessors->IsAccessorPair()) return false;
     423             :   Handle<Object> accessor(access_mode == AccessMode::kLoad
     424       10822 :                               ? Handle<AccessorPair>::cast(accessors)->getter()
     425       10329 :                               : Handle<AccessorPair>::cast(accessors)->setter(),
     426       10329 :                           isolate());
     427       12592 :   if (!accessor->IsJSFunction()) {
     428        3339 :     CallOptimization optimization(isolate(), accessor);
     429        6544 :     if (!optimization.is_simple_api_call()) return false;
     430         172 :     if (optimization.IsCrossContextLazyAccessorPair(*native_context_, *map)) {
     431             :       return false;
     432             :     }
     433             : 
     434             :     CallOptimization::HolderLookup lookup;
     435         166 :     holder = optimization.LookupHolderOfExpectedType(receiver_map, &lookup);
     436         166 :     if (lookup == CallOptimization::kHolderNotFound) return false;
     437             :     DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver,
     438             :                    holder.is_null());
     439             :     DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null());
     440         134 :     if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
     441             :   }
     442        3091 :   if (access_mode == AccessMode::kLoad) {
     443             :     Handle<Name> cached_property_name;
     444        2237 :     if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), accessor)
     445        4474 :             .ToHandle(&cached_property_name)) {
     446           6 :       if (ComputePropertyAccessInfo(map, cached_property_name, access_mode,
     447             :                                     access_info)) {
     448           6 :         return true;
     449             :       }
     450             :     }
     451             :   }
     452        9255 :   *access_info = PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map},
     453        3085 :                                                       accessor, holder);
     454        3085 :   return true;
     455             : }
     456             : 
     457      157712 : bool AccessInfoFactory::ComputePropertyAccessInfo(
     458             :     Handle<Map> map, Handle<Name> name, AccessMode access_mode,
     459      473088 :     PropertyAccessInfo* access_info) const {
     460      157712 :   CHECK(name->IsUniqueName());
     461             : 
     462             :   // Check if it is safe to inline property access for the {map}.
     463      157712 :   if (!CanInlinePropertyAccess(map)) return false;
     464             : 
     465             :   // We support fast inline cases for certain JSObject getters.
     466      268656 :   if (access_mode == AccessMode::kLoad &&
     467      116371 :       LookupSpecialFieldAccessor(map, name, access_info)) {
     468             :     return true;
     469             :   }
     470             : 
     471             :   // Remember the receiver map. We use {map} as loop variable.
     472             :   Handle<Map> receiver_map = map;
     473             :   MaybeHandle<JSObject> holder;
     474      100983 :   do {
     475             :     // Lookup the named property on the {map}.
     476      480806 :     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
     477      480806 :     int const number = descriptors->Search(*name, *map);
     478      240403 :     if (number != DescriptorArray::kNotFound) {
     479      116588 :       PropertyDetails const details = descriptors->GetDetails(number);
     480      116588 :       if (access_mode == AccessMode::kStore ||
     481             :           access_mode == AccessMode::kStoreInLiteral) {
     482             :         // Don't bother optimizing stores to read-only properties.
     483       15112 :         if (details.IsReadOnly()) {
     484             :           return false;
     485             :         }
     486       11931 :         if (details.kind() == kData && !holder.is_null()) {
     487             :           // This is a store to a property not found on the receiver but on a
     488             :           // prototype. According to ES6 section 9.1.9 [[Set]], we need to
     489             :           // create a new data property on the receiver. We can still optimize
     490             :           // if such a transition already exists.
     491        2318 :           return LookupTransition(receiver_map, name, holder, access_info);
     492             :         }
     493             :       }
     494      111089 :       if (details.location() == kField) {
     495      103570 :         if (details.kind() == kData) {
     496             :           return ComputeDataFieldAccessInfo(receiver_map, map, holder, number,
     497      103570 :                                             access_mode, access_info);
     498             :         } else {
     499             :           DCHECK_EQ(kAccessor, details.kind());
     500             :           // TODO(turbofan): Add support for general accessors?
     501             :           return false;
     502             :         }
     503             :       } else {
     504             :         DCHECK_EQ(kDescriptor, details.location());
     505        7519 :         if (details.kind() == kData) {
     506             :           DCHECK(!FLAG_track_constant_fields);
     507           0 :           *access_info = PropertyAccessInfo::DataConstant(
     508             :               MapHandles{receiver_map},
     509           0 :               handle(descriptors->GetStrongValue(number), isolate()), holder);
     510           0 :           return true;
     511             :         } else {
     512             :           DCHECK_EQ(kAccessor, details.kind());
     513             :           return ComputeAccessorDescriptorAccessInfo(receiver_map, name, map,
     514             :                                                      holder, number,
     515        7519 :                                                      access_mode, access_info);
     516             :         }
     517             :       }
     518             :       UNREACHABLE();
     519             :     }
     520             : 
     521             :     // The property wasn't found on {map}. Look on the prototype if appropriate.
     522             : 
     523             :     // Don't search on the prototype chain for special indices in case of
     524             :     // integer indexed exotic objects (see ES6 section 9.4.5).
     525      126597 :     if (map->IsJSTypedArrayMap() && name->IsString() &&
     526         900 :         IsSpecialIndex(String::cast(*name))) {
     527             :       return false;
     528             :     }
     529             : 
     530             :     // Don't search on the prototype when storing in literals.
     531      123808 :     if (access_mode == AccessMode::kStoreInLiteral) {
     532         110 :       return LookupTransition(receiver_map, name, holder, access_info);
     533             :     }
     534             : 
     535             :     // Don't lookup private symbols on the prototype chain.
     536      123698 :     if (name->IsPrivate()) return false;
     537             : 
     538             :     // Walk up the prototype chain.
     539      247394 :     if (!map->prototype()->IsJSObject()) {
     540             :       // Perform the implicit ToObject for primitives here.
     541             :       // Implemented according to ES6 section 7.3.2 GetV (V, P).
     542             :       Handle<JSFunction> constructor;
     543       30719 :       if (Map::GetConstructorFunction(map, native_context())
     544       61438 :               .ToHandle(&constructor)) {
     545       16010 :         map = handle(constructor->initial_map(), isolate());
     546             :         DCHECK(map->prototype()->IsJSObject());
     547       45428 :       } else if (map->prototype()->IsNull(isolate())) {
     548             :         // Store to property not found on the receiver or any prototype, we need
     549             :         // to transition to a new data property.
     550             :         // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
     551       22707 :         if (access_mode == AccessMode::kStore) {
     552       19377 :           return LookupTransition(receiver_map, name, holder, access_info);
     553             :         }
     554             :         // The property was not found, return undefined or throw depending
     555             :         // on the language mode of the load operation.
     556             :         // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
     557        9990 :         *access_info =
     558        3330 :             PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
     559        3330 :         return true;
     560             :       } else {
     561             :         return false;
     562             :       }
     563             :     }
     564             :     Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
     565      100983 :     if (map_prototype->map()->is_deprecated()) {
     566             :       // Try to migrate the prototype object so we don't embed the deprecated
     567             :       // map into the optimized code.
     568           0 :       JSObject::TryMigrateInstance(map_prototype);
     569             :     }
     570             :     map = handle(map_prototype->map(), isolate());
     571             :     holder = map_prototype;
     572             :   } while (CanInlinePropertyAccess(map));
     573             :   return false;
     574             : }
     575             : 
     576        1165 : bool AccessInfoFactory::ComputePropertyAccessInfo(
     577             :     MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
     578        1165 :     PropertyAccessInfo* access_info) const {
     579             :   ZoneVector<PropertyAccessInfo> access_infos(zone());
     580        1685 :   if (ComputePropertyAccessInfos(maps, name, access_mode, &access_infos) &&
     581         520 :       access_infos.size() == 1) {
     582         520 :     *access_info = access_infos.front();
     583         520 :     return true;
     584             :   }
     585             :   return false;
     586             : }
     587             : 
     588      142880 : bool AccessInfoFactory::ComputePropertyAccessInfos(
     589      142880 :     MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
     590      157295 :     ZoneVector<PropertyAccessInfo>* access_infos) const {
     591             :   ZoneVector<PropertyAccessInfo> infos(zone());
     592      142880 :   infos.reserve(maps.size());
     593      427509 :   for (Handle<Map> map : maps) {
     594             :     PropertyAccessInfo access_info;
     595      156499 :     if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
     596             :       return false;
     597             :     }
     598      141749 :     infos.push_back(access_info);
     599             :   }
     600             : 
     601             :   // Merge as many as possible and push into {access_infos}.
     602      397906 :   for (auto it = infos.begin(), end = infos.end(); it != end; ++it) {
     603             :     bool merged = false;
     604      290021 :     for (auto ot = it + 1; ot != end; ++ot) {
     605       14415 :       if (ot->Merge(&(*it), access_mode, zone())) {
     606             :         merged = true;
     607             :         break;
     608             :       }
     609             :     }
     610      141646 :     if (!merged) access_infos->push_back(*it);
     611             :   }
     612             :   return true;
     613             : }
     614             : 
     615             : namespace {
     616             : 
     617       15527 : Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
     618             :                                            ElementsKind that_kind) {
     619       15527 :   if (IsHoleyElementsKind(this_kind)) {
     620             :     that_kind = GetHoleyElementsKind(that_kind);
     621       12224 :   } else if (IsHoleyElementsKind(that_kind)) {
     622             :     this_kind = GetHoleyElementsKind(this_kind);
     623             :   }
     624       15527 :   if (this_kind == that_kind) return Just(this_kind);
     625         790 :   if (IsDoubleElementsKind(that_kind) == IsDoubleElementsKind(this_kind)) {
     626         718 :     if (IsMoreGeneralElementsKindTransition(that_kind, this_kind)) {
     627             :       return Just(this_kind);
     628             :     }
     629         109 :     if (IsMoreGeneralElementsKindTransition(this_kind, that_kind)) {
     630             :       return Just(that_kind);
     631             :     }
     632             :   }
     633             :   return Nothing<ElementsKind>();
     634             : }
     635             : 
     636             : }  // namespace
     637             : 
     638       14779 : bool AccessInfoFactory::ConsolidateElementLoad(
     639             :     MapHandles const& maps, ElementAccessInfo* access_info) const {
     640       14779 :   CHECK(!maps.empty());
     641             :   InstanceType instance_type = maps.front()->instance_type();
     642             :   ElementsKind elements_kind = maps.front()->elements_kind();
     643       44904 :   for (Handle<Map> map : maps) {
     644       32254 :     if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) {
     645             :       return false;
     646             :     }
     647       31054 :     if (!GeneralizeElementsKind(elements_kind, map->elements_kind())
     648       31054 :              .To(&elements_kind)) {
     649             :       return false;
     650             :     }
     651             :   }
     652       13546 :   *access_info = ElementAccessInfo(maps, elements_kind);
     653       13546 :   return true;
     654             : }
     655             : 
     656      116371 : bool AccessInfoFactory::LookupSpecialFieldAccessor(
     657      108196 :     Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) const {
     658             :   // Check for String::length field accessor.
     659      116371 :   if (map->IsStringMap()) {
     660        8175 :     if (Name::Equals(isolate(), name, factory()->length_string())) {
     661        8628 :       *access_info = PropertyAccessInfo::StringLength(MapHandles{map});
     662        2157 :       return true;
     663             :     }
     664             :     return false;
     665             :   }
     666             :   // Check for special JSObject field accessors.
     667             :   FieldIndex field_index;
     668      108196 :   if (Accessors::IsJSObjectFieldAccessor(isolate(), map, name, &field_index)) {
     669             :     Type field_type = Type::NonInternal();
     670             :     MachineRepresentation field_representation = MachineRepresentation::kTagged;
     671        8989 :     if (map->IsJSArrayMap()) {
     672             :       DCHECK(Name::Equals(isolate(), factory()->length_string(), name));
     673             :       // The JSArray::length property is a smi in the range
     674             :       // [0, FixedDoubleArray::kMaxLength] in case of fast double
     675             :       // elements, a smi in the range [0, FixedArray::kMaxLength]
     676             :       // in case of other fast elements, and [0, kMaxUInt32] in
     677             :       // case of other arrays.
     678        8989 :       if (IsDoubleElementsKind(map->elements_kind())) {
     679         290 :         field_type = type_cache_->kFixedDoubleArrayLengthType;
     680             :         field_representation = MachineRepresentation::kTaggedSigned;
     681        8699 :       } else if (IsFastElementsKind(map->elements_kind())) {
     682        8456 :         field_type = type_cache_->kFixedArrayLengthType;
     683             :         field_representation = MachineRepresentation::kTaggedSigned;
     684             :       } else {
     685         243 :         field_type = type_cache_->kJSArrayLengthType;
     686             :       }
     687             :     }
     688             :     // Special fields are always mutable.
     689       26967 :     *access_info = PropertyAccessInfo::DataField(
     690             :         PropertyConstness::kMutable, MapHandles{map}, field_index,
     691        8989 :         field_representation, field_type);
     692             :     return true;
     693             :   }
     694             :   return false;
     695             : }
     696             : 
     697       21805 : bool AccessInfoFactory::LookupTransition(
     698             :     Handle<Map> map, Handle<Name> name, MaybeHandle<JSObject> holder,
     699       88472 :     PropertyAccessInfo* access_info) const {
     700             :   // Check if the {map} has a data transition with the given {name}.
     701             :   Map transition =
     702       21805 :       TransitionsAccessor(isolate(), map).SearchTransition(*name, kData, NONE);
     703       21805 :   if (transition.is_null()) return false;
     704             : 
     705             :   Handle<Map> transition_map(transition, isolate());
     706       21771 :   int const number = transition_map->LastAdded();
     707             :   PropertyDetails const details =
     708       21771 :       transition_map->instance_descriptors()->GetDetails(number);
     709             :   // Don't bother optimizing stores to read-only properties.
     710       21771 :   if (details.IsReadOnly()) return false;
     711             :   // TODO(bmeurer): Handle transition to data constant?
     712       21771 :   if (details.location() != kField) return false;
     713             :   int const index = details.field_index();
     714             :   Representation details_representation = details.representation();
     715             :   FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index,
     716       21771 :                                                         details_representation);
     717             :   Type field_type = Type::NonInternal();
     718             :   MaybeHandle<Map> field_map;
     719             :   MachineRepresentation field_representation = MachineRepresentation::kTagged;
     720       21771 :   if (details_representation.IsSmi()) {
     721             :     field_type = Type::SignedSmall();
     722             :     field_representation = MachineRepresentation::kTaggedSigned;
     723        3388 :   } else if (details_representation.IsDouble()) {
     724         147 :     field_type = type_cache_->kFloat64;
     725             :     field_representation = MachineRepresentation::kFloat64;
     726        3241 :   } else if (details_representation.IsHeapObject()) {
     727             :     // Extract the field type from the property details (make sure its
     728             :     // representation is TaggedPointer to reflect the heap object case).
     729             :     field_representation = MachineRepresentation::kTaggedPointer;
     730             :     Handle<FieldType> descriptors_field_type(
     731        1708 :         transition_map->instance_descriptors()->GetFieldType(number),
     732        1708 :         isolate());
     733         854 :     if (descriptors_field_type->IsNone()) {
     734             :       // Store is not safe if the field type was cleared.
     735             :       return false;
     736         854 :     } else if (descriptors_field_type->IsClass()) {
     737             :       MapRef transition_map_ref(broker(), transition_map);
     738             :       transition_map_ref
     739         125 :           .SerializeOwnDescriptors();  // TODO(neis): Remove later.
     740         125 :       dependencies()->DependOnFieldType(transition_map_ref, number);
     741             :       // Remember the field map, and try to infer a useful type.
     742         250 :       Handle<Map> map(descriptors_field_type->AsClass(), isolate());
     743         125 :       field_type = Type::For(MapRef(broker(), map));
     744             :       field_map = MaybeHandle<Map>(map);
     745             :     }
     746             :   }
     747       21771 :   dependencies()->DependOnTransition(MapRef(broker(), transition_map));
     748             :   // Transitioning stores are never stores to constant fields.
     749       65313 :   *access_info = PropertyAccessInfo::DataField(
     750             :       PropertyConstness::kMutable, MapHandles{map}, field_index,
     751       21771 :       field_representation, field_type, field_map, holder, transition_map);
     752       21771 :   return true;
     753             : }
     754             : 
     755        8175 : Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
     756             : 
     757             : }  // namespace compiler
     758             : }  // namespace internal
     759      178779 : }  // namespace v8

Generated by: LCOV version 1.10