LCOV - code coverage report
Current view: top level - src/compiler - property-access-builder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 85 89 95.5 %
Date: 2019-01-20 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      265717 : Graph* PropertyAccessBuilder::graph() const { return jsgraph()->graph(); }
      24             : 
      25       60515 : Isolate* PropertyAccessBuilder::isolate() const { return jsgraph()->isolate(); }
      26             : 
      27           0 : CommonOperatorBuilder* PropertyAccessBuilder::common() const {
      28           0 :   return jsgraph()->common();
      29             : }
      30             : 
      31      170729 : SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const {
      32      170729 :   return jsgraph()->simplified();
      33             : }
      34             : 
      35      154128 : bool HasOnlyStringMaps(MapHandles const& maps) {
      36      317039 :   for (auto map : maps) {
      37      154891 :     if (!map->IsStringMap()) return false;
      38             :   }
      39             :   return true;
      40             : }
      41             : 
      42             : namespace {
      43             : 
      44      115726 : bool HasOnlyNumberMaps(MapHandles const& maps) {
      45      233018 :   for (auto map : maps) {
      46      115734 :     if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
      47             :   }
      48             :   return true;
      49             : }
      50             : 
      51             : }  // namespace
      52             : 
      53      123277 : bool PropertyAccessBuilder::TryBuildStringCheck(MapHandles const& maps,
      54             :                                                 Node** receiver, Node** effect,
      55             :                                                 Node* control) {
      56      123277 :   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       22653 :                          *effect, control);
      62        7551 :     return true;
      63             :   }
      64             :   return false;
      65             : }
      66             : 
      67      115726 : bool PropertyAccessBuilder::TryBuildNumberCheck(MapHandles const& maps,
      68             :                                                 Node** receiver, Node** effect,
      69             :                                                 Node* control) {
      70      115726 :   if (HasOnlyNumberMaps(maps)) {
      71             :     // Monomorphic number access (we also deal with Smis here).
      72             :     *receiver = *effect =
      73             :         graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), *receiver,
      74        4674 :                          *effect, control);
      75        1558 :     return true;
      76             :   }
      77             :   return false;
      78             : }
      79             : 
      80             : namespace {
      81             : 
      82      145561 : bool NeedsCheckHeapObject(Node* receiver) {
      83      145561 :   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        2058 :       Node* control = NodeProperties::GetControlInput(receiver);
     120        2058 :       if (control->opcode() != IrOpcode::kMerge) return true;
     121        3696 :       for (int i = 0; i < receiver->InputCount() - 1; ++i) {
     122        2498 :         if (NeedsCheckHeapObject(receiver->InputAt(i))) return true;
     123             :       }
     124             :       return false;
     125             :     }
     126             :     default:
     127       48716 :       return true;
     128             :   }
     129             : }
     130             : 
     131             : }  // namespace
     132             : 
     133      143063 : Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
     134             :                                                   Node* control) {
     135      143063 :   if (NeedsCheckHeapObject(receiver)) {
     136             :     receiver = *effect = graph()->NewNode(simplified()->CheckHeapObject(),
     137      147465 :                                           receiver, *effect, control);
     138             :   }
     139      143064 :   return receiver;
     140             : }
     141             : 
     142      141241 : void PropertyAccessBuilder::BuildCheckMaps(
     143             :     Node* receiver, Node** effect, Node* control,
     144      107482 :     std::vector<Handle<Map>> const& receiver_maps) {
     145             :   HeapObjectMatcher m(receiver);
     146      141241 :   if (m.HasValue()) {
     147             :     Handle<Map> receiver_map(m.Value()->map(), isolate());
     148       58919 :     if (receiver_map->is_stable()) {
     149      107482 :       for (Handle<Map> map : receiver_maps) {
     150       53741 :         if (map.is_identical_to(receiver_map)) {
     151       53741 :           dependencies()->DependOnStableMap(MapRef(broker(), receiver_map));
     152      141242 :           return;
     153             :         }
     154             :       }
     155             :     }
     156             :   }
     157             :   ZoneHandleSet<Map> maps;
     158             :   CheckMapsFlags flags = CheckMapsFlag::kNone;
     159      269988 :   for (Handle<Map> map : receiver_maps) {
     160       94988 :     maps.insert(map, graph()->zone());
     161       94988 :     if (map->is_migration_target()) {
     162             :       flags |= CheckMapsFlag::kTryMigrateInstance;
     163             :     }
     164             :   }
     165             :   *effect = graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
     166      262502 :                              *effect, control);
     167             : }
     168             : 
     169        1585 : Node* PropertyAccessBuilder::BuildCheckValue(Node* receiver, Node** effect,
     170             :                                              Node* control,
     171         121 :                                              Handle<HeapObject> value) {
     172             :   HeapObjectMatcher m(receiver);
     173        1585 :   if (m.Is(value)) return receiver;
     174         121 :   Node* expected = jsgraph()->HeapConstant(value);
     175             :   Node* check =
     176         121 :       graph()->NewNode(simplified()->ReferenceEqual(), receiver, expected);
     177             :   *effect =
     178             :       graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongValue),
     179         363 :                        check, *effect, control);
     180         121 :   return expected;
     181             : }
     182             : 
     183       25169 : Node* PropertyAccessBuilder::ResolveHolder(
     184         221 :     PropertyAccessInfo const& access_info, Node* receiver) {
     185             :   Handle<JSObject> holder;
     186       25169 :   if (access_info.holder().ToHandle(&holder)) {
     187         221 :     return jsgraph()->Constant(holder);
     188             :   }
     189             :   return receiver;
     190             : }
     191             : 
     192       25168 : Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
     193         727 :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver) {
     194             :   // Optimize immutable property loads.
     195             :   HeapObjectMatcher m(receiver);
     196       28360 :   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        1596 :                       LookupIterator::OWN_SKIP_INTERCEPTOR);
     209        1596 :     if (it.state() == LookupIterator::DATA) {
     210             :       bool is_readonly_non_configurable =
     211        2202 :           it.IsReadOnly() && !it.IsConfigurable();
     212        1461 :       if (is_readonly_non_configurable ||
     213             :           (FLAG_track_constant_fields && access_info.IsDataConstantField())) {
     214        1454 :         Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
     215         727 :         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           0 :           map.SerializeOwnDescriptors();  // TODO(neis): Remove later.
     223           0 :           dependencies()->DependOnFieldType(map, it.GetFieldDescriptorIndex());
     224             :         }
     225         727 :         return value;
     226             :       }
     227             :     }
     228             :   }
     229             :   return nullptr;
     230             : }
     231             : 
     232       25169 : Node* PropertyAccessBuilder::BuildLoadDataField(
     233       24441 :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver,
     234        2250 :     Node** effect, Node** control) {
     235             :   DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
     236       25169 :   receiver = ResolveHolder(access_info, receiver);
     237       25168 :   if (Node* value =
     238       25168 :           TryBuildLoadConstantDataField(name, access_info, receiver)) {
     239             :     return value;
     240             :   }
     241             : 
     242             :   FieldIndex const field_index = access_info.field_index();
     243             :   Type const field_type = access_info.field_type();
     244             :   MachineRepresentation const field_representation =
     245       24441 :       access_info.field_representation();
     246             :   Node* storage = receiver;
     247       24441 :   if (!field_index.is_inobject()) {
     248             :     storage = *effect = graph()->NewNode(
     249             :         simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
     250         732 :         storage, *effect, *control);
     251             :   }
     252             :   FieldAccess field_access = {
     253             :       kTaggedBase,
     254             :       field_index.offset(),
     255             :       name,
     256             :       MaybeHandle<Map>(),
     257             :       field_type,
     258             :       MachineType::TypeForRepresentation(field_representation),
     259             :       kFullWriteBarrier,
     260       24441 :       LoadSensitivity::kCritical};
     261       24441 :   if (field_representation == MachineRepresentation::kFloat64) {
     262         659 :     if (!field_index.is_inobject() || field_index.is_hidden_field() ||
     263             :         !FLAG_unbox_double_fields) {
     264             :       FieldAccess const storage_access = {kTaggedBase,
     265             :                                           field_index.offset(),
     266             :                                           name,
     267             :                                           MaybeHandle<Map>(),
     268             :                                           Type::OtherInternal(),
     269             :                                           MachineType::TaggedPointer(),
     270             :                                           kPointerWriteBarrier,
     271             :                                           LoadSensitivity::kCritical};
     272             :       storage = *effect = graph()->NewNode(
     273         111 :           simplified()->LoadField(storage_access), storage, *effect, *control);
     274          37 :       field_access.offset = HeapNumber::kValueOffset;
     275          37 :       field_access.name = MaybeHandle<Name>();
     276             :     }
     277       24093 :   } else if (field_representation == MachineRepresentation::kTaggedPointer) {
     278             :     // Remember the map of the field value, if its map is stable. This is
     279             :     // used by the LoadElimination to eliminate map checks on the result.
     280             :     Handle<Map> field_map;
     281        6743 :     if (access_info.field_map().ToHandle(&field_map)) {
     282        1132 :       if (field_map->is_stable()) {
     283        1125 :         dependencies()->DependOnStableMap(MapRef(broker(), field_map));
     284        1125 :         field_access.map = field_map;
     285             :       }
     286             :     }
     287             :   }
     288             :   Node* value = *effect = graph()->NewNode(
     289       73324 :       simplified()->LoadField(field_access), storage, *effect, *control);
     290       24442 :   return value;
     291             : }
     292             : 
     293             : }  // namespace compiler
     294             : }  // namespace internal
     295      183867 : }  // namespace v8

Generated by: LCOV version 1.10