LCOV - code coverage report
Current view: top level - src/compiler - property-access-builder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 88 96 91.7 %
Date: 2019-04-19 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      155435 : bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps) {
      36      163831 :   for (auto map : maps) {
      37             :     MapRef map_ref(broker, map);
      38      155993 :     if (!map_ref.IsStringMap()) return false;
      39             :   }
      40             :   return true;
      41             : }
      42             : 
      43             : namespace {
      44             : 
      45      113007 : bool HasOnlyNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
      46      114300 :   for (auto map : maps) {
      47             :     MapRef map_ref(broker, map);
      48      113007 :     if (map_ref.instance_type() != HEAP_NUMBER_TYPE) return false;
      49             :   }
      50             :   return true;
      51             : }
      52             : 
      53             : }  // namespace
      54             : 
      55      120374 : bool PropertyAccessBuilder::TryBuildStringCheck(JSHeapBroker* broker,
      56             :                                                 MapHandles const& maps,
      57             :                                                 Node** receiver, Node** effect,
      58             :                                                 Node* control) {
      59      120374 :   if (HasOnlyStringMaps(broker, maps)) {
      60             :     // Monormorphic string access (ignoring the fact that there are multiple
      61             :     // String maps).
      62             :     *receiver = *effect =
      63       14734 :         graph()->NewNode(simplified()->CheckString(VectorSlotPair()), *receiver,
      64        7367 :                          *effect, control);
      65        7367 :     return true;
      66             :   }
      67             :   return false;
      68             : }
      69             : 
      70      113007 : bool PropertyAccessBuilder::TryBuildNumberCheck(JSHeapBroker* broker,
      71             :                                                 MapHandles const& maps,
      72             :                                                 Node** receiver, Node** effect,
      73             :                                                 Node* control) {
      74      113007 :   if (HasOnlyNumberMaps(broker, maps)) {
      75             :     // Monomorphic number access (we also deal with Smis here).
      76             :     *receiver = *effect =
      77        2586 :         graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), *receiver,
      78        1293 :                          *effect, control);
      79        1293 :     return true;
      80             :   }
      81             :   return false;
      82             : }
      83             : 
      84             : namespace {
      85             : 
      86      145012 : bool NeedsCheckHeapObject(Node* receiver) {
      87      145012 :   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        1938 :       Node* control = NodeProperties::GetControlInput(receiver);
     124        1938 :       if (control->opcode() != IrOpcode::kMerge) return true;
     125        3774 :       for (int i = 0; i < receiver->InputCount() - 1; ++i) {
     126        2503 :         if (NeedsCheckHeapObject(receiver->InputAt(i))) return true;
     127             :       }
     128             :       return false;
     129             :     }
     130             :     default:
     131       47924 :       return true;
     132             :   }
     133             : }
     134             : 
     135             : }  // namespace
     136             : 
     137      142509 : Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
     138             :                                                   Node* control) {
     139      142509 :   if (NeedsCheckHeapObject(receiver)) {
     140       48316 :     receiver = *effect = graph()->NewNode(simplified()->CheckHeapObject(),
     141       48316 :                                           receiver, *effect, control);
     142             :   }
     143      142509 :   return receiver;
     144             : }
     145             : 
     146      140245 : void PropertyAccessBuilder::BuildCheckMaps(Node* receiver, Node** effect,
     147             :                                            Node* control,
     148             :                                            MapHandles const& receiver_maps) {
     149             :   HeapObjectMatcher m(receiver);
     150      140245 :   if (m.HasValue()) {
     151       60183 :     MapRef receiver_map = m.Ref(broker()).map();
     152       60183 :     if (receiver_map.is_stable()) {
     153       55118 :       for (Handle<Map> map : receiver_maps) {
     154       55118 :         if (MapRef(broker(), map).equals(receiver_map)) {
     155       55118 :           dependencies()->DependOnStableMap(receiver_map);
     156             :           return;
     157             :         }
     158             :       }
     159             :     }
     160             :   }
     161             :   ZoneHandleSet<Map> maps;
     162             :   CheckMapsFlags flags = CheckMapsFlag::kNone;
     163      177651 :   for (Handle<Map> map : receiver_maps) {
     164             :     MapRef receiver_map(broker(), map);
     165       92524 :     maps.insert(receiver_map.object(), graph()->zone());
     166       92524 :     if (receiver_map.is_migration_target()) {
     167             :       flags |= CheckMapsFlag::kTryMigrateInstance;
     168             :     }
     169             :   }
     170      170254 :   *effect = graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
     171       85127 :                              *effect, control);
     172             : }
     173             : 
     174         954 : Node* PropertyAccessBuilder::BuildCheckValue(Node* receiver, Node** effect,
     175             :                                              Node* control,
     176             :                                              Handle<HeapObject> value) {
     177             :   HeapObjectMatcher m(receiver);
     178         954 :   if (m.Is(value)) return receiver;
     179          29 :   Node* expected = jsgraph()->HeapConstant(value);
     180             :   Node* check =
     181          29 :       graph()->NewNode(simplified()->ReferenceEqual(), receiver, expected);
     182             :   *effect =
     183          58 :       graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongValue),
     184          29 :                        check, *effect, control);
     185          29 :   return expected;
     186             : }
     187             : 
     188           0 : Node* PropertyAccessBuilder::ResolveHolder(
     189             :     PropertyAccessInfo const& access_info, Node* receiver) {
     190             :   Handle<JSObject> holder;
     191       25062 :   if (access_info.holder().ToHandle(&holder)) {
     192        1452 :     return jsgraph()->Constant(holder);
     193             :   }
     194             :   return receiver;
     195             : }
     196             : 
     197       95773 : Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
     198             :     NameRef const& name, PropertyAccessInfo const& access_info,
     199             :     Node* receiver) {
     200             :   // Optimize immutable property loads.
     201             : 
     202             :   // First, determine if we have a constant holder to load from.
     203             :   Handle<JSObject> holder;
     204             :   // If {access_info} has a holder, just use it.
     205       95773 :   if (!access_info.holder().ToHandle(&holder)) {
     206             :     // Otherwise, try to match the {receiver} as a constant.
     207             :     HeapObjectMatcher m(receiver);
     208      144635 :     if (!m.HasValue() || !m.Ref(broker()).IsJSObject()) return nullptr;
     209             : 
     210             :     // Let us make sure the actual map of the constant receiver is among
     211             :     // the maps in {access_info}.
     212       48970 :     MapRef receiver_map = m.Ref(broker()).map();
     213       48970 :     if (std::find_if(access_info.receiver_maps().begin(),
     214             :                      access_info.receiver_maps().end(), [&](Handle<Map> map) {
     215       48970 :                        return map.address() == receiver_map.object().address();
     216             :                      }) == access_info.receiver_maps().end()) {
     217             :       // The map of the receiver is not in the feedback, let us bail out.
     218             :       return nullptr;
     219             :     }
     220             :     holder = Handle<JSObject>::cast(m.Value());
     221             :   }
     222             : 
     223             :   // TODO(ishell): Use something simpler like
     224             :   //
     225             :   // Handle<Object> value =
     226             :   //     JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()),
     227             :   //                              Representation::Tagged(), field_index);
     228             :   //
     229             :   // here, once we have the immutable bit in the access_info.
     230             : 
     231             :   // TODO(turbofan): Given that we already have the field_index here, we
     232             :   // might be smarter in the future and not rely on the LookupIterator.
     233             :   LookupIterator it(isolate(), holder, name.object(),
     234      144844 :                     LookupIterator::OWN_SKIP_INTERCEPTOR);
     235       72422 :   if (it.state() == LookupIterator::DATA) {
     236       73045 :     bool is_readonly_non_configurable = it.IsReadOnly() && !it.IsConfigurable();
     237       72290 :     if (is_readonly_non_configurable ||
     238             :         (FLAG_track_constant_fields && access_info.IsDataConstantField())) {
     239       70711 :       Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
     240       70711 :       if (!is_readonly_non_configurable) {
     241             :         // It's necessary to add dependency on the map that introduced
     242             :         // the field.
     243             :         DCHECK(access_info.IsDataConstantField());
     244             :         DCHECK(!it.is_dictionary_holder());
     245             :         MapRef map(broker(),
     246             :                    handle(it.GetHolder<HeapObject>()->map(), isolate()));
     247       69970 :         map.SerializeOwnDescriptors();  // TODO(neis): Remove later.
     248       69970 :         if (dependencies()->DependOnFieldConstness(
     249             :                 map, it.GetFieldDescriptorIndex()) !=
     250             :             PropertyConstness::kConst) {
     251           0 :           return nullptr;
     252             :         }
     253             :       }
     254             :       return value;
     255             :     }
     256             :   }
     257             :   return nullptr;
     258             : }
     259             : 
     260       95773 : Node* PropertyAccessBuilder::BuildLoadDataField(
     261             :     NameRef const& name, PropertyAccessInfo const& access_info, Node* receiver,
     262             :     Node** effect, Node** control) {
     263             :   DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
     264       95773 :   if (Node* value =
     265       95773 :           TryBuildLoadConstantDataField(name, access_info, receiver)) {
     266             :     return value;
     267             :   }
     268             : 
     269             :   FieldIndex const field_index = access_info.field_index();
     270             :   Type const field_type = access_info.field_type();
     271             :   MachineRepresentation const field_representation =
     272       25062 :       access_info.field_representation();
     273             :   Node* storage = ResolveHolder(access_info, receiver);
     274       25062 :   if (!field_index.is_inobject()) {
     275        1296 :     storage = *effect = graph()->NewNode(
     276        1296 :         simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
     277         648 :         storage, *effect, *control);
     278             :   }
     279             :   FieldAccess field_access = {
     280             :       kTaggedBase,
     281             :       field_index.offset(),
     282             :       name.object(),
     283             :       MaybeHandle<Map>(),
     284             :       field_type,
     285             :       MachineType::TypeForRepresentation(field_representation),
     286             :       kFullWriteBarrier,
     287       25062 :       LoadSensitivity::kCritical};
     288       25062 :   if (field_representation == MachineRepresentation::kFloat64) {
     289         663 :     if (!field_index.is_inobject() || field_index.is_hidden_field() ||
     290             :         !FLAG_unbox_double_fields) {
     291             :       FieldAccess const storage_access = {
     292             :           kTaggedBase,           field_index.offset(),
     293             :           name.object(),         MaybeHandle<Map>(),
     294             :           Type::OtherInternal(), MachineType::TaggedPointer(),
     295          37 :           kPointerWriteBarrier,  LoadSensitivity::kCritical};
     296          37 :       storage = *effect = graph()->NewNode(
     297          37 :           simplified()->LoadField(storage_access), storage, *effect, *control);
     298          37 :       field_access.offset = HeapNumber::kValueOffset;
     299          37 :       field_access.name = MaybeHandle<Name>();
     300             :     }
     301       24712 :   } else if (field_representation == MachineRepresentation::kTaggedPointer ||
     302             :              field_representation ==
     303             :                  MachineRepresentation::kCompressedPointer) {
     304             :     // Remember the map of the field value, if its map is stable. This is
     305             :     // used by the LoadElimination to eliminate map checks on the result.
     306             :     Handle<Map> field_map;
     307        7580 :     if (access_info.field_map().ToHandle(&field_map)) {
     308             :       MapRef field_map_ref(broker(), field_map);
     309        2386 :       if (field_map_ref.is_stable()) {
     310        2382 :         dependencies()->DependOnStableMap(field_map_ref);
     311        2382 :         field_access.map = field_map;
     312             :       }
     313             :     }
     314             :   }
     315       25062 :   Node* value = *effect = graph()->NewNode(
     316       25062 :       simplified()->LoadField(field_access), storage, *effect, *control);
     317       25062 :   return value;
     318             : }
     319             : 
     320             : }  // namespace compiler
     321             : }  // namespace internal
     322      122036 : }  // namespace v8

Generated by: LCOV version 1.10