LCOV - code coverage report
Current view: top level - src/compiler - property-access-builder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 89 92 96.7 %
Date: 2017-10-20 Functions: 10 14 71.4 %

          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/compilation-dependencies.h"
       8             : #include "src/compiler/access-builder.h"
       9             : #include "src/compiler/access-info.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             : 
      15             : #include "src/field-index-inl.h"
      16             : #include "src/isolate-inl.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : namespace compiler {
      21             : 
      22      228742 : Graph* PropertyAccessBuilder::graph() const { return jsgraph()->graph(); }
      23             : 
      24       57273 : Isolate* PropertyAccessBuilder::isolate() const { return jsgraph()->isolate(); }
      25             : 
      26           0 : CommonOperatorBuilder* PropertyAccessBuilder::common() const {
      27           0 :   return jsgraph()->common();
      28             : }
      29             : 
      30      146379 : SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const {
      31      146379 :   return jsgraph()->simplified();
      32             : }
      33             : 
      34       26327 : bool HasOnlyStringMaps(MapHandles const& maps) {
      35      254869 :   for (auto map : maps) {
      36      125896 :     if (!map->IsStringMap()) return false;
      37             :   }
      38             :   return true;
      39             : }
      40             : 
      41             : namespace {
      42             : 
      43             : bool HasOnlyNumberMaps(MapHandles const& maps) {
      44      191099 :   for (auto map : maps) {
      45       95424 :     if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
      46             :   }
      47             :   return true;
      48             : }
      49             : 
      50             : bool HasOnlySequentialStringMaps(MapHandles const& maps) {
      51       10862 :   for (auto map : maps) {
      52        3950 :     if (!map->IsStringMap()) return false;
      53        3950 :     if (!StringShape(map->instance_type()).IsSequential()) {
      54             :       return false;
      55             :     }
      56             :   }
      57             :   return true;
      58             : }
      59             : 
      60             : }  // namespace
      61             : 
      62       99000 : bool PropertyAccessBuilder::TryBuildStringCheck(MapHandles const& maps,
      63             :                                                 Node** receiver, Node** effect,
      64             :                                                 Node* control) {
      65       99000 :   if (HasOnlyStringMaps(maps)) {
      66        3576 :     if (HasOnlySequentialStringMaps(maps)) {
      67             :       *receiver = *effect = graph()->NewNode(simplified()->CheckSeqString(),
      68        8886 :                                              *receiver, *effect, control);
      69             :     } else {
      70             :       // Monormorphic string access (ignoring the fact that there are multiple
      71             :       // String maps).
      72             :       *receiver = *effect = graph()->NewNode(simplified()->CheckString(),
      73        1842 :                                              *receiver, *effect, control);
      74             :     }
      75             :     return true;
      76             :   }
      77             :   return false;
      78             : }
      79             : 
      80       95424 : bool PropertyAccessBuilder::TryBuildNumberCheck(MapHandles const& maps,
      81             :                                                 Node** receiver, Node** effect,
      82             :                                                 Node* control) {
      83       95424 :   if (HasOnlyNumberMaps(maps)) {
      84             :     // Monomorphic number access (we also deal with Smis here).
      85             :     *receiver = *effect = graph()->NewNode(simplified()->CheckNumber(),
      86         753 :                                            *receiver, *effect, control);
      87         251 :     return true;
      88             :   }
      89             :   return false;
      90             : }
      91             : 
      92             : namespace {
      93             : 
      94      131874 : bool NeedsCheckHeapObject(Node* receiver) {
      95      131874 :   switch (receiver->opcode()) {
      96             :     case IrOpcode::kHeapConstant:
      97             :     case IrOpcode::kJSCreate:
      98             :     case IrOpcode::kJSCreateArguments:
      99             :     case IrOpcode::kJSCreateArray:
     100             :     case IrOpcode::kJSCreateClosure:
     101             :     case IrOpcode::kJSCreateIterResultObject:
     102             :     case IrOpcode::kJSCreateLiteralArray:
     103             :     case IrOpcode::kJSCreateEmptyLiteralArray:
     104             :     case IrOpcode::kJSCreateLiteralObject:
     105             :     case IrOpcode::kJSCreateEmptyLiteralObject:
     106             :     case IrOpcode::kJSCreateLiteralRegExp:
     107             :     case IrOpcode::kJSCreateGeneratorObject:
     108             :     case IrOpcode::kJSConvertReceiver:
     109             :     case IrOpcode::kJSConstructForwardVarargs:
     110             :     case IrOpcode::kJSConstruct:
     111             :     case IrOpcode::kJSConstructWithArrayLike:
     112             :     case IrOpcode::kJSConstructWithSpread:
     113             :     case IrOpcode::kJSToName:
     114             :     case IrOpcode::kJSToString:
     115             :     case IrOpcode::kJSToObject:
     116             :     case IrOpcode::kTypeOf:
     117             :     case IrOpcode::kJSGetSuperConstructor:
     118             :       return false;
     119             :     case IrOpcode::kPhi: {
     120        2313 :       Node* control = NodeProperties::GetControlInput(receiver);
     121        2313 :       if (control->opcode() != IrOpcode::kMerge) return true;
     122        3021 :       for (int i = 0; i < receiver->InputCount() - 1; ++i) {
     123        2492 :         if (NeedsCheckHeapObject(receiver->InputAt(i))) return true;
     124             :       }
     125             :       return false;
     126             :     }
     127             :     default:
     128       44733 :       return true;
     129             :   }
     130             : }
     131             : 
     132             : }  // namespace
     133             : 
     134      129382 : Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
     135             :                                                   Node* control) {
     136      129382 :   if (NeedsCheckHeapObject(receiver)) {
     137             :     receiver = *effect = graph()->NewNode(simplified()->CheckHeapObject(),
     138      135243 :                                           receiver, *effect, control);
     139             :   }
     140      129382 :   return receiver;
     141             : }
     142             : 
     143      129431 : void PropertyAccessBuilder::BuildCheckMaps(
     144             :     Node* receiver, Node** effect, Node* control,
     145       53386 :     std::vector<Handle<Map>> const& receiver_maps) {
     146             :   HeapObjectMatcher m(receiver);
     147      129431 :   if (m.HasValue()) {
     148             :     Handle<Map> receiver_map(m.Value()->map(), isolate());
     149       57273 :     if (receiver_map->is_stable()) {
     150      106772 :       for (Handle<Map> map : receiver_maps) {
     151       53386 :         if (map.is_identical_to(receiver_map)) {
     152       53386 :           dependencies()->AssumeMapStable(receiver_map);
     153      129431 :           return;
     154             :         }
     155             :       }
     156             :     }
     157             :   }
     158             :   ZoneHandleSet<Map> maps;
     159             :   CheckMapsFlags flags = CheckMapsFlag::kNone;
     160      234453 :   for (Handle<Map> map : receiver_maps) {
     161       82363 :     maps.insert(map, graph()->zone());
     162       82363 :     if (map->is_migration_target()) {
     163             :       flags |= CheckMapsFlag::kTryMigrateInstance;
     164             :     }
     165             :   }
     166             :   *effect = graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
     167      228135 :                              *effect, control);
     168             : }
     169             : 
     170       40248 : void PropertyAccessBuilder::AssumePrototypesStable(
     171             :     Handle<Context> native_context,
     172       41137 :     std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) {
     173             :   // Determine actual holder and perform prototype chain checks.
     174      121633 :   for (auto map : receiver_maps) {
     175             :     // Perform the implicit ToObject for primitives here.
     176             :     // Implemented according to ES6 section 7.3.2 GetV (V, P).
     177             :     Handle<JSFunction> constructor;
     178       41137 :     if (Map::GetConstructorFunction(map, native_context)
     179       82274 :             .ToHandle(&constructor)) {
     180        3499 :       map = handle(constructor->initial_map(), holder->GetIsolate());
     181             :     }
     182       41137 :     dependencies()->AssumePrototypeMapsStable(map, holder);
     183             :   }
     184       40248 : }
     185             : 
     186       21023 : Node* PropertyAccessBuilder::ResolveHolder(
     187         119 :     PropertyAccessInfo const& access_info, Node* receiver) {
     188             :   Handle<JSObject> holder;
     189       21023 :   if (access_info.holder().ToHandle(&holder)) {
     190         119 :     return jsgraph()->Constant(holder);
     191             :   }
     192             :   return receiver;
     193             : }
     194             : 
     195       21023 : Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
     196         299 :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver) {
     197             :   // Optimize immutable property loads.
     198             :   HeapObjectMatcher m(receiver);
     199       22359 :   if (m.HasValue() && m.Value()->IsJSObject()) {
     200             :     // TODO(ishell): Use something simpler like
     201             :     //
     202             :     // Handle<Object> value =
     203             :     //     JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()),
     204             :     //                              Representation::Tagged(), field_index);
     205             :     //
     206             :     // here, once we have the immutable bit in the access_info.
     207             : 
     208             :     // TODO(turbofan): Given that we already have the field_index here, we
     209             :     // might be smarter in the future and not rely on the LookupIterator,
     210             :     // but for now let's just do what Crankshaft does.
     211        1336 :     LookupIterator it(m.Value(), name, LookupIterator::OWN_SKIP_INTERCEPTOR);
     212        1336 :     if (it.state() == LookupIterator::DATA) {
     213             :       bool is_reaonly_non_configurable =
     214        1486 :           it.IsReadOnly() && !it.IsConfigurable();
     215        1173 :       if (is_reaonly_non_configurable ||
     216             :           (FLAG_track_constant_fields && access_info.IsDataConstantField())) {
     217         598 :         Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
     218         299 :         if (!is_reaonly_non_configurable) {
     219             :           // It's necessary to add dependency on the map that introduced
     220             :           // the field.
     221             :           DCHECK(access_info.IsDataConstantField());
     222             :           DCHECK(!it.is_dictionary_holder());
     223           0 :           Handle<Map> field_owner_map = it.GetFieldOwnerMap();
     224             :           dependencies()->AssumeFieldOwner(field_owner_map);
     225             :         }
     226         299 :         return value;
     227             :       }
     228             :     }
     229             :   }
     230             :   return nullptr;
     231             : }
     232             : 
     233       21023 : Node* PropertyAccessBuilder::BuildLoadDataField(
     234       20724 :     Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver,
     235         573 :     Node** effect, Node** control) {
     236             :   DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
     237       21023 :   receiver = ResolveHolder(access_info, receiver);
     238       21023 :   if (Node* value =
     239       21023 :           TryBuildLoadConstantDataField(name, access_info, receiver)) {
     240             :     return value;
     241             :   }
     242             : 
     243             :   FieldIndex const field_index = access_info.field_index();
     244             :   Type* const field_type = access_info.field_type();
     245             :   MachineRepresentation const field_representation =
     246       20724 :       access_info.field_representation();
     247             :   Node* storage = receiver;
     248       20724 :   if (!field_index.is_inobject()) {
     249             :     storage = *effect = graph()->NewNode(
     250             :         simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
     251        2010 :         storage, *effect, *control);
     252             :   }
     253             :   FieldAccess field_access = {
     254             :       kTaggedBase,
     255             :       field_index.offset(),
     256             :       name,
     257             :       MaybeHandle<Map>(),
     258             :       field_type,
     259             :       MachineType::TypeForRepresentation(field_representation),
     260       62172 :       kFullWriteBarrier};
     261       20724 :   if (field_representation == MachineRepresentation::kFloat64) {
     262         704 :     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          64 :                                           kPointerWriteBarrier};
     271             :       storage = *effect = graph()->NewNode(
     272          96 :           simplified()->LoadField(storage_access), storage, *effect, *control);
     273          32 :       field_access.offset = HeapNumber::kValueOffset;
     274          32 :       field_access.name = MaybeHandle<Name>();
     275             :     }
     276       20356 :   } else if (field_representation == MachineRepresentation::kTaggedPointer) {
     277             :     // Remember the map of the field value, if its map is stable. This is
     278             :     // used by the LoadElimination to eliminate map checks on the result.
     279             :     Handle<Map> field_map;
     280        4856 :     if (access_info.field_map().ToHandle(&field_map)) {
     281         581 :       if (field_map->is_stable()) {
     282         573 :         dependencies()->AssumeMapStable(field_map);
     283         573 :         field_access.map = field_map;
     284             :       }
     285             :     }
     286             :   }
     287             :   Node* value = *effect = graph()->NewNode(
     288       62172 :       simplified()->LoadField(field_access), storage, *effect, *control);
     289       20724 :   return value;
     290             : }
     291             : 
     292             : }  // namespace compiler
     293             : }  // namespace internal
     294             : }  // namespace v8

Generated by: LCOV version 1.10