LCOV - code coverage report
Current view: top level - src/compiler - property-access-builder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 88 91 96.7 %
Date: 2019-02-19 Functions: 13 17 76.5 %

          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      273478 : Graph* PropertyAccessBuilder::graph() const { return jsgraph()->graph(); }
      24             : 
      25      201817 : Isolate* PropertyAccessBuilder::isolate() const { return jsgraph()->isolate(); }
      26             : 
      27           0 : CommonOperatorBuilder* PropertyAccessBuilder::common() const {
      28           0 :   return jsgraph()->common();
      29             : }
      30             : 
      31      175886 : SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const {
      32      175886 :   return jsgraph()->simplified();
      33             : }
      34             : 
      35      156824 : bool HasOnlyStringMaps(MapHandles const& maps) {
      36      322263 :   for (auto map : maps) {
      37      157581 :     if (!map->IsStringMap()) return false;
      38             :   }
      39             :   return true;
      40             : }
      41             : 
      42             : namespace {
      43             : 
      44      114869 : bool HasOnlyNumberMaps(MapHandles const& maps) {
      45      231028 :   for (auto map : maps) {
      46      114869 :     if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
      47             :   }
      48             :   return true;
      49             : }
      50             : 
      51             : }  // namespace
      52             : 
      53      122265 : bool PropertyAccessBuilder::TryBuildStringCheck(MapHandles const& maps,
      54             :                                                 Node** receiver, Node** effect,
      55             :                                                 Node* control) {
      56      122265 :   if (HasOnlyStringMaps(maps)) {
      57             :     // Monormorphic string access (ignoring the fact that there are multiple
      58             :     // String maps).
      59             :     *receiver = *effect =
      60             :         graph()->NewNode(simplified()->CheckString(VectorSlotPair()), *receiver,
      61       22188 :                          *effect, control);
      62        7396 :     return true;
      63             :   }
      64             :   return false;
      65             : }
      66             : 
      67      114869 : bool PropertyAccessBuilder::TryBuildNumberCheck(MapHandles const& maps,
      68             :                                                 Node** receiver, Node** effect,
      69             :                                                 Node* control) {
      70      114869 :   if (HasOnlyNumberMaps(maps)) {
      71             :     // Monomorphic number access (we also deal with Smis here).
      72             :     *receiver = *effect =
      73             :         graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), *receiver,
      74        3870 :                          *effect, control);
      75        1290 :     return true;
      76             :   }
      77             :   return false;
      78             : }
      79             : 
      80             : namespace {
      81             : 
      82      146994 : bool NeedsCheckHeapObject(Node* receiver) {
      83      146994 :   switch (receiver->opcode()) {
      84             :     case IrOpcode::kConvertReceiver:
      85             :     case IrOpcode::kHeapConstant:
      86             :     case IrOpcode::kJSCloneObject:
      87             :     case IrOpcode::kJSConstruct:
      88             :     case IrOpcode::kJSConstructForwardVarargs:
      89             :     case IrOpcode::kJSConstructWithArrayLike:
      90             :     case IrOpcode::kJSConstructWithSpread:
      91             :     case IrOpcode::kJSCreate:
      92             :     case IrOpcode::kJSCreateArguments:
      93             :     case IrOpcode::kJSCreateArray:
      94             :     case IrOpcode::kJSCreateArrayFromIterable:
      95             :     case IrOpcode::kJSCreateArrayIterator:
      96             :     case IrOpcode::kJSCreateAsyncFunctionObject:
      97             :     case IrOpcode::kJSCreateBoundFunction:
      98             :     case IrOpcode::kJSCreateClosure:
      99             :     case IrOpcode::kJSCreateCollectionIterator:
     100             :     case IrOpcode::kJSCreateEmptyLiteralArray:
     101             :     case IrOpcode::kJSCreateEmptyLiteralObject:
     102             :     case IrOpcode::kJSCreateGeneratorObject:
     103             :     case IrOpcode::kJSCreateIterResultObject:
     104             :     case IrOpcode::kJSCreateKeyValueArray:
     105             :     case IrOpcode::kJSCreateLiteralArray:
     106             :     case IrOpcode::kJSCreateLiteralObject:
     107             :     case IrOpcode::kJSCreateLiteralRegExp:
     108             :     case IrOpcode::kJSCreateObject:
     109             :     case IrOpcode::kJSCreatePromise:
     110             :     case IrOpcode::kJSCreateStringIterator:
     111             :     case IrOpcode::kJSCreateTypedArray:
     112             :     case IrOpcode::kJSGetSuperConstructor:
     113             :     case IrOpcode::kJSToName:
     114             :     case IrOpcode::kJSToObject:
     115             :     case IrOpcode::kJSToString:
     116             :     case IrOpcode::kTypeOf:
     117             :       return false;
     118             :     case IrOpcode::kPhi: {
     119        2114 :       Node* control = NodeProperties::GetControlInput(receiver);
     120        2114 :       if (control->opcode() != IrOpcode::kMerge) return true;
     121        4167 :       for (int i = 0; i < receiver->InputCount() - 1; ++i) {
     122        2758 :         if (NeedsCheckHeapObject(receiver->InputAt(i))) return true;
     123             :       }
     124             :       return false;
     125             :     }
     126             :     default:
     127       49371 :       return true;
     128             :   }
     129             : }
     130             : 
     131             : }  // namespace
     132             : 
     133      144236 : Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
     134             :                                                   Node* control) {
     135      144236 :   if (NeedsCheckHeapObject(receiver)) {
     136             :     receiver = *effect = graph()->NewNode(simplified()->CheckHeapObject(),
     137      149436 :                                           receiver, *effect, control);
     138             :   }
     139      144236 :   return receiver;
     140             : }
     141             : 
     142      142054 : void PropertyAccessBuilder::BuildCheckMaps(
     143             :     Node* receiver, Node** effect, Node* control,
     144      105562 :     std::vector<Handle<Map>> const& receiver_maps) {
     145             :   HeapObjectMatcher m(receiver);
     146      142054 :   if (m.HasValue()) {
     147             :     Handle<Map> receiver_map(m.Value()->map(), isolate());
     148       57812 :     if (receiver_map->is_stable()) {
     149      105562 :       for (Handle<Map> map : receiver_maps) {
     150       52781 :         if (map.is_identical_to(receiver_map)) {
     151       52781 :           dependencies()->DependOnStableMap(MapRef(broker(), receiver_map));
     152      142054 :           return;
     153             :         }
     154             :       }
     155             :     }
     156             :   }
     157             :   ZoneHandleSet<Map> maps;
     158             :   CheckMapsFlags flags = CheckMapsFlag::kNone;
     159      276138 :   for (Handle<Map> map : receiver_maps) {
     160       97592 :     maps.insert(map, graph()->zone());
     161       97592 :     if (map->is_migration_target()) {
     162             :       flags |= CheckMapsFlag::kTryMigrateInstance;
     163             :     }
     164             :   }
     165             :   *effect = graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
     166      267819 :                              *effect, control);
     167             : }
     168             : 
     169        1035 : Node* PropertyAccessBuilder::BuildCheckValue(Node* receiver, Node** effect,
     170             :                                              Node* control,
     171          26 :                                              Handle<HeapObject> value) {
     172             :   HeapObjectMatcher m(receiver);
     173        1035 :   if (m.Is(value)) return receiver;
     174          26 :   Node* expected = jsgraph()->HeapConstant(value);
     175             :   Node* check =
     176          26 :       graph()->NewNode(simplified()->ReferenceEqual(), receiver, expected);
     177             :   *effect =
     178             :       graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongValue),
     179          78 :                        check, *effect, control);
     180          26 :   return expected;
     181             : }
     182             : 
     183       98622 : Node* PropertyAccessBuilder::ResolveHolder(
     184       26688 :     PropertyAccessInfo const& access_info, Node* receiver) {
     185             :   Handle<JSObject> holder;
     186       98622 :   if (access_info.holder().ToHandle(&holder)) {
     187       26688 :     return jsgraph()->Constant(holder);
     188             :   }
     189             :   return receiver;
     190             : }
     191             : 
     192       98622 : Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
     193      212314 :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver) {
     194             :   // Optimize immutable property loads.
     195             :   HeapObjectMatcher m(receiver);
     196      245584 :   if (m.HasValue() && m.Value()->IsJSObject()) {
     197             :     // TODO(ishell): Use something simpler like
     198             :     //
     199             :     // Handle<Object> value =
     200             :     //     JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()),
     201             :     //                              Representation::Tagged(), field_index);
     202             :     //
     203             :     // here, once we have the immutable bit in the access_info.
     204             : 
     205             :     // TODO(turbofan): Given that we already have the field_index here, we
     206             :     // might be smarter in the future and not rely on the LookupIterator.
     207             :     LookupIterator it(isolate(), m.Value(), name,
     208       73481 :                       LookupIterator::OWN_SKIP_INTERCEPTOR);
     209       73481 :     if (it.state() == LookupIterator::DATA) {
     210             :       bool is_readonly_non_configurable =
     211       74101 :           it.IsReadOnly() && !it.IsConfigurable();
     212      145948 :       if (is_readonly_non_configurable ||
     213             :           (FLAG_track_constant_fields && access_info.IsDataConstantField())) {
     214      142532 :         Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
     215       71266 :         if (!is_readonly_non_configurable) {
     216             :           // It's necessary to add dependency on the map that introduced
     217             :           // the field.
     218             :           DCHECK(access_info.IsDataConstantField());
     219             :           DCHECK(!it.is_dictionary_holder());
     220             :           MapRef map(broker(),
     221             :                      handle(it.GetHolder<HeapObject>()->map(), isolate()));
     222       70524 :           map.SerializeOwnDescriptors();  // TODO(neis): Remove later.
     223       70524 :           if (dependencies()->DependOnFieldConstness(
     224      141048 :                   map, it.GetFieldDescriptorIndex()) !=
     225             :               PropertyConstness::kConst) {
     226           0 :             return nullptr;
     227             :           }
     228             :         }
     229       71266 :         return value;
     230             :       }
     231             :     }
     232             :   }
     233             :   return nullptr;
     234             : }
     235             : 
     236       98622 : Node* PropertyAccessBuilder::BuildLoadDataField(
     237       27356 :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver,
     238        3252 :     Node** effect, Node** control) {
     239             :   DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
     240       98622 :   receiver = ResolveHolder(access_info, receiver);
     241       98622 :   if (Node* value =
     242       98622 :           TryBuildLoadConstantDataField(name, access_info, receiver)) {
     243             :     return value;
     244             :   }
     245             : 
     246             :   FieldIndex const field_index = access_info.field_index();
     247             :   Type const field_type = access_info.field_type();
     248             :   MachineRepresentation const field_representation =
     249       27356 :       access_info.field_representation();
     250             :   Node* storage = receiver;
     251       27356 :   if (!field_index.is_inobject()) {
     252             :     storage = *effect = graph()->NewNode(
     253             :         simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
     254        2010 :         storage, *effect, *control);
     255             :   }
     256             :   FieldAccess field_access = {
     257             :       kTaggedBase,
     258             :       field_index.offset(),
     259             :       name,
     260             :       MaybeHandle<Map>(),
     261             :       field_type,
     262             :       MachineType::TypeForRepresentation(field_representation),
     263             :       kFullWriteBarrier,
     264       27356 :       LoadSensitivity::kCritical};
     265       27356 :   if (field_representation == MachineRepresentation::kFloat64) {
     266         665 :     if (!field_index.is_inobject() || field_index.is_hidden_field() ||
     267             :         !FLAG_unbox_double_fields) {
     268             :       FieldAccess const storage_access = {kTaggedBase,
     269             :                                           field_index.offset(),
     270             :                                           name,
     271             :                                           MaybeHandle<Map>(),
     272             :                                           Type::OtherInternal(),
     273             :                                           MachineType::TaggedPointer(),
     274             :                                           kPointerWriteBarrier,
     275             :                                           LoadSensitivity::kCritical};
     276             :       storage = *effect = graph()->NewNode(
     277         111 :           simplified()->LoadField(storage_access), storage, *effect, *control);
     278          37 :       field_access.offset = HeapNumber::kValueOffset;
     279          37 :       field_access.name = MaybeHandle<Name>();
     280             :     }
     281       27005 :   } else if (field_representation == MachineRepresentation::kTaggedPointer) {
     282             :     // Remember the map of the field value, if its map is stable. This is
     283             :     // used by the LoadElimination to eliminate map checks on the result.
     284             :     Handle<Map> field_map;
     285        7798 :     if (access_info.field_map().ToHandle(&field_map)) {
     286        1630 :       if (field_map->is_stable()) {
     287        1626 :         dependencies()->DependOnStableMap(MapRef(broker(), field_map));
     288        1626 :         field_access.map = field_map;
     289             :       }
     290             :     }
     291             :   }
     292             :   Node* value = *effect = graph()->NewNode(
     293       82068 :       simplified()->LoadField(field_access), storage, *effect, *control);
     294       27356 :   return value;
     295             : }
     296             : 
     297             : }  // namespace compiler
     298             : }  // namespace internal
     299      178779 : }  // namespace v8

Generated by: LCOV version 1.10