LCOV - code coverage report
Current view: top level - src/compiler - property-access-builder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 82 90 91.1 %
Date: 2019-03-21 Functions: 11 16 68.8 %

          Line data    Source code
       1             : // Copyright 2017 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 "src/compiler/property-access-builder.h"
       6             : 
       7             : #include "src/compiler/access-builder.h"
       8             : #include "src/compiler/access-info.h"
       9             : #include "src/compiler/compilation-dependencies.h"
      10             : #include "src/compiler/js-graph.h"
      11             : #include "src/compiler/node-matchers.h"
      12             : #include "src/compiler/simplified-operator.h"
      13             : #include "src/lookup.h"
      14             : #include "src/objects/heap-number.h"
      15             : 
      16             : #include "src/field-index-inl.h"
      17             : #include "src/isolate-inl.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : namespace compiler {
      22             : 
      23           0 : Graph* PropertyAccessBuilder::graph() const { return jsgraph()->graph(); }
      24             : 
      25           0 : Isolate* PropertyAccessBuilder::isolate() const { return jsgraph()->isolate(); }
      26             : 
      27           0 : CommonOperatorBuilder* PropertyAccessBuilder::common() const {
      28           0 :   return jsgraph()->common();
      29             : }
      30             : 
      31           0 : SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const {
      32           0 :   return jsgraph()->simplified();
      33             : }
      34             : 
      35      154028 : bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps) {
      36      162309 :   for (auto map : maps) {
      37             :     MapRef map_ref(broker, map);
      38      154639 :     if (!map_ref.IsStringMap()) return false;
      39             :   }
      40             :   return true;
      41             : }
      42             : 
      43             : namespace {
      44             : 
      45      111722 : bool HasOnlyNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
      46      113012 :   for (auto map : maps) {
      47             :     MapRef map_ref(broker, map);
      48      111722 :     if (map_ref.instance_type() != HEAP_NUMBER_TYPE) return false;
      49             :   }
      50             :   return true;
      51             : }
      52             : 
      53             : }  // namespace
      54             : 
      55      118915 : bool PropertyAccessBuilder::TryBuildStringCheck(JSHeapBroker* broker,
      56             :                                                 MapHandles const& maps,
      57             :                                                 Node** receiver, Node** effect,
      58             :                                                 Node* control) {
      59      118915 :   if (HasOnlyStringMaps(broker, maps)) {
      60             :     // Monormorphic string access (ignoring the fact that there are multiple
      61             :     // String maps).
      62             :     *receiver = *effect =
      63       14386 :         graph()->NewNode(simplified()->CheckString(VectorSlotPair()), *receiver,
      64        7193 :                          *effect, control);
      65        7193 :     return true;
      66             :   }
      67             :   return false;
      68             : }
      69             : 
      70      111722 : bool PropertyAccessBuilder::TryBuildNumberCheck(JSHeapBroker* broker,
      71             :                                                 MapHandles const& maps,
      72             :                                                 Node** receiver, Node** effect,
      73             :                                                 Node* control) {
      74      111722 :   if (HasOnlyNumberMaps(broker, maps)) {
      75             :     // Monomorphic number access (we also deal with Smis here).
      76             :     *receiver = *effect =
      77        2580 :         graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), *receiver,
      78        1290 :                          *effect, control);
      79        1290 :     return true;
      80             :   }
      81             :   return false;
      82             : }
      83             : 
      84             : namespace {
      85             : 
      86      144188 : bool NeedsCheckHeapObject(Node* receiver) {
      87      144188 :   switch (receiver->opcode()) {
      88             :     case IrOpcode::kConvertReceiver:
      89             :     case IrOpcode::kHeapConstant:
      90             :     case IrOpcode::kJSCloneObject:
      91             :     case IrOpcode::kJSConstruct:
      92             :     case IrOpcode::kJSConstructForwardVarargs:
      93             :     case IrOpcode::kJSConstructWithArrayLike:
      94             :     case IrOpcode::kJSConstructWithSpread:
      95             :     case IrOpcode::kJSCreate:
      96             :     case IrOpcode::kJSCreateArguments:
      97             :     case IrOpcode::kJSCreateArray:
      98             :     case IrOpcode::kJSCreateArrayFromIterable:
      99             :     case IrOpcode::kJSCreateArrayIterator:
     100             :     case IrOpcode::kJSCreateAsyncFunctionObject:
     101             :     case IrOpcode::kJSCreateBoundFunction:
     102             :     case IrOpcode::kJSCreateClosure:
     103             :     case IrOpcode::kJSCreateCollectionIterator:
     104             :     case IrOpcode::kJSCreateEmptyLiteralArray:
     105             :     case IrOpcode::kJSCreateEmptyLiteralObject:
     106             :     case IrOpcode::kJSCreateGeneratorObject:
     107             :     case IrOpcode::kJSCreateIterResultObject:
     108             :     case IrOpcode::kJSCreateKeyValueArray:
     109             :     case IrOpcode::kJSCreateLiteralArray:
     110             :     case IrOpcode::kJSCreateLiteralObject:
     111             :     case IrOpcode::kJSCreateLiteralRegExp:
     112             :     case IrOpcode::kJSCreateObject:
     113             :     case IrOpcode::kJSCreatePromise:
     114             :     case IrOpcode::kJSCreateStringIterator:
     115             :     case IrOpcode::kJSCreateTypedArray:
     116             :     case IrOpcode::kJSGetSuperConstructor:
     117             :     case IrOpcode::kJSToName:
     118             :     case IrOpcode::kJSToObject:
     119             :     case IrOpcode::kJSToString:
     120             :     case IrOpcode::kTypeOf:
     121             :       return false;
     122             :     case IrOpcode::kPhi: {
     123        2143 :       Node* control = NodeProperties::GetControlInput(receiver);
     124        2143 :       if (control->opcode() != IrOpcode::kMerge) return true;
     125        4137 :       for (int i = 0; i < receiver->InputCount() - 1; ++i) {
     126        2748 :         if (NeedsCheckHeapObject(receiver->InputAt(i))) return true;
     127             :       }
     128             :       return false;
     129             :     }
     130             :     default:
     131       48847 :       return true;
     132             :   }
     133             : }
     134             : 
     135             : }  // namespace
     136             : 
     137      141440 : Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
     138             :                                                   Node* control) {
     139      141440 :   if (NeedsCheckHeapObject(receiver)) {
     140       49311 :     receiver = *effect = graph()->NewNode(simplified()->CheckHeapObject(),
     141       49311 :                                           receiver, *effect, control);
     142             :   }
     143      141440 :   return receiver;
     144             : }
     145             : 
     146      139103 : void PropertyAccessBuilder::BuildCheckMaps(Node* receiver, Node** effect,
     147             :                                            Node* control,
     148             :                                            MapHandles const& receiver_maps) {
     149             :   HeapObjectMatcher m(receiver);
     150      139103 :   if (m.HasValue()) {
     151       58999 :     MapRef receiver_map = m.Ref(broker()).AsHeapObject().map();
     152       58999 :     if (receiver_map.is_stable()) {
     153       53835 :       for (Handle<Map> map : receiver_maps) {
     154       53835 :         if (MapRef(broker(), map).equals(receiver_map)) {
     155       53835 :           dependencies()->DependOnStableMap(receiver_map);
     156             :           return;
     157             :         }
     158             :       }
     159             :     }
     160             :   }
     161             :   ZoneHandleSet<Map> maps;
     162             :   CheckMapsFlags flags = CheckMapsFlag::kNone;
     163      177744 :   for (Handle<Map> map : receiver_maps) {
     164             :     MapRef receiver_map(broker(), map);
     165       92476 :     maps.insert(receiver_map.object(), graph()->zone());
     166       92476 :     if (receiver_map.is_migration_target()) {
     167             :       flags |= CheckMapsFlag::kTryMigrateInstance;
     168             :     }
     169             :   }
     170      170536 :   *effect = graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
     171       85268 :                              *effect, control);
     172             : }
     173             : 
     174         955 : Node* PropertyAccessBuilder::BuildCheckValue(Node* receiver, Node** effect,
     175             :                                              Node* control,
     176             :                                              Handle<HeapObject> value) {
     177             :   HeapObjectMatcher m(receiver);
     178         955 :   if (m.Is(value)) return receiver;
     179          24 :   Node* expected = jsgraph()->HeapConstant(value);
     180             :   Node* check =
     181          24 :       graph()->NewNode(simplified()->ReferenceEqual(), receiver, expected);
     182             :   *effect =
     183          48 :       graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongValue),
     184          24 :                        check, *effect, control);
     185          24 :   return expected;
     186             : }
     187             : 
     188           0 : Node* PropertyAccessBuilder::ResolveHolder(
     189             :     PropertyAccessInfo const& access_info, Node* receiver) {
     190             :   Handle<JSObject> holder;
     191       94901 :   if (access_info.holder().ToHandle(&holder)) {
     192       22567 :     return jsgraph()->Constant(holder);
     193             :   }
     194             :   return receiver;
     195             : }
     196             : 
     197       94901 : Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
     198             :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver) {
     199             :   // Optimize immutable property loads.
     200             :   HeapObjectMatcher m(receiver);
     201      165291 :   if (m.HasValue() && m.Value()->IsJSObject()) {
     202             :     // TODO(ishell): Use something simpler like
     203             :     //
     204             :     // Handle<Object> value =
     205             :     //     JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()),
     206             :     //                              Representation::Tagged(), field_index);
     207             :     //
     208             :     // here, once we have the immutable bit in the access_info.
     209             : 
     210             :     // TODO(turbofan): Given that we already have the field_index here, we
     211             :     // might be smarter in the future and not rely on the LookupIterator.
     212             :     LookupIterator it(isolate(), m.Value(), name,
     213       70390 :                       LookupIterator::OWN_SKIP_INTERCEPTOR);
     214       70390 :     if (it.state() == LookupIterator::DATA) {
     215             :       bool is_readonly_non_configurable =
     216       71017 :           it.IsReadOnly() && !it.IsConfigurable();
     217       70255 :       if (is_readonly_non_configurable ||
     218             :           (FLAG_track_constant_fields && access_info.IsDataConstantField())) {
     219       68643 :         Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
     220       68643 :         if (!is_readonly_non_configurable) {
     221             :           // It's necessary to add dependency on the map that introduced
     222             :           // the field.
     223             :           DCHECK(access_info.IsDataConstantField());
     224             :           DCHECK(!it.is_dictionary_holder());
     225             :           MapRef map(broker(),
     226             :                      handle(it.GetHolder<HeapObject>()->map(), isolate()));
     227       67895 :           map.SerializeOwnDescriptors();  // TODO(neis): Remove later.
     228       67895 :           if (dependencies()->DependOnFieldConstness(
     229             :                   map, it.GetFieldDescriptorIndex()) !=
     230             :               PropertyConstness::kConst) {
     231           0 :             return nullptr;
     232             :           }
     233             :         }
     234             :         return value;
     235             :       }
     236             :     }
     237             :   }
     238             :   return nullptr;
     239             : }
     240             : 
     241       94901 : Node* PropertyAccessBuilder::BuildLoadDataField(
     242             :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver,
     243             :     Node** effect, Node** control) {
     244             :   DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
     245             :   receiver = ResolveHolder(access_info, receiver);
     246       94901 :   if (Node* value =
     247       94901 :           TryBuildLoadConstantDataField(name, access_info, receiver)) {
     248             :     return value;
     249             :   }
     250             : 
     251             :   FieldIndex const field_index = access_info.field_index();
     252             :   Type const field_type = access_info.field_type();
     253             :   MachineRepresentation const field_representation =
     254       26258 :       access_info.field_representation();
     255             :   Node* storage = receiver;
     256       26258 :   if (!field_index.is_inobject()) {
     257        1342 :     storage = *effect = graph()->NewNode(
     258        1342 :         simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
     259         671 :         storage, *effect, *control);
     260             :   }
     261             :   FieldAccess field_access = {
     262             :       kTaggedBase,
     263             :       field_index.offset(),
     264             :       name,
     265             :       MaybeHandle<Map>(),
     266             :       field_type,
     267             :       MachineType::TypeForRepresentation(field_representation),
     268             :       kFullWriteBarrier,
     269       26258 :       LoadSensitivity::kCritical};
     270       26258 :   if (field_representation == MachineRepresentation::kFloat64) {
     271             :     if (!field_index.is_inobject() || field_index.is_hidden_field() ||
     272             :         !FLAG_unbox_double_fields) {
     273             :       FieldAccess const storage_access = {kTaggedBase,
     274             :                                           field_index.offset(),
     275             :                                           name,
     276             :                                           MaybeHandle<Map>(),
     277             :                                           Type::OtherInternal(),
     278             :                                           MachineType::TaggedPointer(),
     279             :                                           kPointerWriteBarrier,
     280             :                                           LoadSensitivity::kCritical};
     281         382 :       storage = *effect = graph()->NewNode(
     282         382 :           simplified()->LoadField(storage_access), storage, *effect, *control);
     283         382 :       field_access.offset = HeapNumber::kValueOffset;
     284         382 :       field_access.name = MaybeHandle<Name>();
     285             :     }
     286       25876 :   } else if (field_representation == MachineRepresentation::kTaggedPointer) {
     287             :     // Remember the map of the field value, if its map is stable. This is
     288             :     // used by the LoadElimination to eliminate map checks on the result.
     289             :     Handle<Map> field_map;
     290        8103 :     if (access_info.field_map().ToHandle(&field_map)) {
     291        2634 :       if (field_map->is_stable()) {
     292        2630 :         dependencies()->DependOnStableMap(MapRef(broker(), field_map));
     293        2630 :         field_access.map = field_map;
     294             :       }
     295             :     }
     296             :   }
     297       26258 :   Node* value = *effect = graph()->NewNode(
     298       26258 :       simplified()->LoadField(field_access), storage, *effect, *control);
     299       26258 :   return value;
     300             : }
     301             : 
     302             : }  // namespace compiler
     303             : }  // namespace internal
     304      120216 : }  // namespace v8

Generated by: LCOV version 1.10