LCOV - code coverage report
Current view: top level - src/ic - handler-configuration.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 78 78 100.0 %
Date: 2019-02-19 Functions: 18 18 100.0 %

          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/ic/handler-configuration.h"
       6             : 
       7             : #include "src/code-factory.h"
       8             : #include "src/ic/handler-configuration-inl.h"
       9             : #include "src/objects/data-handler-inl.h"
      10             : #include "src/objects/maybe-object.h"
      11             : #include "src/transitions.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16             : namespace {
      17             : 
      18             : template <typename BitField>
      19       40735 : Handle<Smi> SetBitFieldValue(Isolate* isolate, Handle<Smi> smi_handler,
      20             :                              typename BitField::FieldType value) {
      21             :   int config = smi_handler->value();
      22       81470 :   config = BitField::update(config, true);
      23       40736 :   return handle(Smi::FromInt(config), isolate);
      24             : }
      25             : 
      26             : // TODO(ishell): Remove templatezation once we move common bits from
      27             : // Load/StoreHandler to the base class.
      28             : template <typename ICHandler, bool fill_handler = true>
      29     1213860 : int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
      30             :                             Handle<Smi>* smi_handler, Handle<Map> receiver_map,
      31             :                             Handle<JSReceiver> holder, MaybeObjectHandle data1,
      32             :                             MaybeObjectHandle maybe_data2) {
      33             :   int checks_count = 0;
      34             :   // Holder-is-receiver case itself does not add entries unless there is an
      35             :   // optional data2 value provided.
      36             : 
      37     2359050 :   if (receiver_map->IsPrimitiveMap() ||
      38             :       receiver_map->is_access_check_needed()) {
      39             :     DCHECK(!receiver_map->IsJSGlobalObjectMap());
      40             :     // The validity cell check for primitive and global proxy receivers does
      41             :     // not guarantee that certain native context ever had access to other
      42             :     // native context. However, a handler created for one native context could
      43             :     // be used in other native context through the megamorphic stub cache.
      44             :     // So we record the original native context to which this handler
      45             :     // corresponds.
      46             :     if (fill_handler) {
      47       39051 :       Handle<Context> native_context = isolate->native_context();
      48       78102 :       handler->set_data2(HeapObjectReference::Weak(*native_context));
      49             :     } else {
      50             :       // Enable access checks on receiver.
      51             :       typedef typename ICHandler::DoAccessCheckOnReceiverBits Bit;
      52       39050 :       *smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true);
      53             :     }
      54             :     checks_count++;
      55     1747877 :   } else if (receiver_map->is_dictionary_map() &&
      56             :              !receiver_map->IsJSGlobalObjectMap()) {
      57             :     if (!fill_handler) {
      58             :       // Enable lookup on receiver.
      59             :       typedef typename ICHandler::LookupOnReceiverBits Bit;
      60        1685 :       *smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true);
      61             :     }
      62             :   }
      63             :   if (fill_handler) {
      64     1213121 :     handler->set_data1(*data1);
      65             :   }
      66     1213864 :   if (!maybe_data2.is_null()) {
      67             :     if (fill_handler) {
      68             :       // This value will go either to data2 or data3 slot depending on whether
      69             :       // data2 slot is already occupied by native context.
      70        3886 :       if (checks_count == 0) {
      71        7752 :         handler->set_data2(*maybe_data2);
      72             :       } else {
      73             :         DCHECK_EQ(1, checks_count);
      74          20 :         handler->set_data3(*maybe_data2);
      75             :       }
      76             :     }
      77        7771 :     checks_count++;
      78             :   }
      79     1213864 :   return checks_count;
      80             : }
      81             : 
      82             : // Returns 0 if the validity cell check is enough to ensure that the
      83             : // prototype chain from |receiver_map| till |holder| did not change.
      84             : // If the |holder| is an empty handle then the full prototype chain is
      85             : // checked.
      86             : // Returns -1 if the handler has to be compiled or the number of prototype
      87             : // checks otherwise.
      88             : template <typename ICHandler>
      89             : int GetPrototypeCheckCount(
      90             :     Isolate* isolate, Handle<Smi>* smi_handler, Handle<Map> receiver_map,
      91             :     Handle<JSReceiver> holder, MaybeObjectHandle data1,
      92             :     MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
      93             :   DCHECK_NOT_NULL(smi_handler);
      94             :   return InitPrototypeChecksImpl<ICHandler, false>(isolate, Handle<ICHandler>(),
      95             :                                                    smi_handler, receiver_map,
      96      607299 :                                                    holder, data1, maybe_data2);
      97             : }
      98             : 
      99             : template <typename ICHandler>
     100             : void InitPrototypeChecks(Isolate* isolate, Handle<ICHandler> handler,
     101             :                          Handle<Map> receiver_map, Handle<JSReceiver> holder,
     102             :                          MaybeObjectHandle data1,
     103             :                          MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
     104      606563 :   InitPrototypeChecksImpl<ICHandler, true>(
     105             :       isolate, handler, nullptr, receiver_map, holder, data1, maybe_data2);
     106             : }
     107             : 
     108             : }  // namespace
     109             : 
     110             : // static
     111      363642 : Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
     112             :                                               Handle<Map> receiver_map,
     113             :                                               Handle<JSReceiver> holder,
     114             :                                               Handle<Smi> smi_handler,
     115             :                                               MaybeObjectHandle maybe_data1,
     116             :                                               MaybeObjectHandle maybe_data2) {
     117             :   MaybeObjectHandle data1;
     118      363642 :   if (maybe_data1.is_null()) {
     119             :     data1 = MaybeObjectHandle::Weak(holder);
     120             :   } else {
     121       16232 :     data1 = maybe_data1;
     122             :   }
     123             : 
     124             :   int checks_count = GetPrototypeCheckCount<LoadHandler>(
     125             :       isolate, &smi_handler, receiver_map, holder, data1, maybe_data2);
     126             : 
     127             :   Handle<Object> validity_cell =
     128      363645 :       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
     129             : 
     130      363643 :   int data_count = 1 + checks_count;
     131      363643 :   Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
     132             : 
     133      727285 :   handler->set_smi_handler(*smi_handler);
     134      363644 :   handler->set_validity_cell(*validity_cell);
     135             :   InitPrototypeChecks(isolate, handler, receiver_map, holder, data1,
     136             :                       maybe_data2);
     137      363647 :   return handler;
     138             : }
     139             : 
     140             : // static
     141       73900 : Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
     142             :                                           Handle<Map> receiver_map,
     143             :                                           const MaybeObjectHandle& holder,
     144             :                                           Handle<Smi> smi_handler) {
     145             :   Handle<JSReceiver> end;  // null handle, means full prototype chain lookup.
     146       73900 :   MaybeObjectHandle data1 = holder;
     147             :   int checks_count = GetPrototypeCheckCount<LoadHandler>(
     148             :       isolate, &smi_handler, receiver_map, end, data1);
     149             : 
     150             :   Handle<Object> validity_cell =
     151       73900 :       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
     152      147800 :   if (validity_cell->IsSmi()) {
     153             :     DCHECK_EQ(0, checks_count);
     154             :     // Lookup on receiver isn't supported in case of a simple smi handler.
     155        1482 :     if (!LookupOnReceiverBits::decode(smi_handler->value())) return smi_handler;
     156             :   }
     157             : 
     158       73159 :   int data_count = 1 + checks_count;
     159       73159 :   Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
     160             : 
     161      146318 :   handler->set_smi_handler(*smi_handler);
     162       73159 :   handler->set_validity_cell(*validity_cell);
     163             :   InitPrototypeChecks(isolate, handler, receiver_map, end, data1);
     164       73159 :   return handler;
     165             : }
     166             : 
     167             : // static
     168       18845 : KeyedAccessLoadMode LoadHandler::GetKeyedAccessLoadMode(MaybeObject handler) {
     169             :   DisallowHeapAllocation no_gc;
     170       18845 :   if (handler->IsSmi()) {
     171       37406 :     int const raw_handler = handler.ToSmi().value();
     172       18703 :     Kind const kind = KindBits::decode(raw_handler);
     173       37405 :     if ((kind == kElement || kind == kIndexedString) &&
     174             :         AllowOutOfBoundsBits::decode(raw_handler)) {
     175             :       return LOAD_IGNORE_OUT_OF_BOUNDS;
     176             :     }
     177             :   }
     178             :   return STANDARD_LOAD;
     179             : }
     180             : 
     181             : // static
     182        1674 : Handle<Object> StoreHandler::StoreElementTransition(
     183             :     Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition,
     184             :     KeyedAccessStoreMode store_mode) {
     185             :   Handle<Code> stub =
     186        3348 :       CodeFactory::ElementsTransitionAndStore(isolate, store_mode).code();
     187             :   Handle<Object> validity_cell =
     188        1674 :       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
     189        1674 :   Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
     190        3348 :   handler->set_smi_handler(*stub);
     191        1674 :   handler->set_validity_cell(*validity_cell);
     192        3348 :   handler->set_data1(HeapObjectReference::Weak(*transition));
     193        1674 :   return handler;
     194             : }
     195             : 
     196      422551 : MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
     197             :                                                 Handle<Map> transition_map) {
     198      422552 :   bool is_dictionary_map = transition_map->is_dictionary_map();
     199             : #ifdef DEBUG
     200             :   if (!is_dictionary_map) {
     201             :     int descriptor = transition_map->LastAdded();
     202             :     Handle<DescriptorArray> descriptors(transition_map->instance_descriptors(),
     203             :                                         isolate);
     204             :     PropertyDetails details = descriptors->GetDetails(descriptor);
     205             :     if (descriptors->GetKey(descriptor)->IsPrivate()) {
     206             :       DCHECK_EQ(DONT_ENUM, details.attributes());
     207             :     } else {
     208             :       DCHECK_EQ(NONE, details.attributes());
     209             :     }
     210             :     Representation representation = details.representation();
     211             :     DCHECK(!representation.IsNone());
     212             :   }
     213             : #endif
     214             :   // Declarative handlers don't support access checks.
     215             :   DCHECK(!transition_map->is_access_check_needed());
     216             : 
     217             :   // Get validity cell value if it is necessary for the handler.
     218             :   Handle<Object> validity_cell;
     219      805708 :   if (is_dictionary_map || !transition_map->IsPrototypeValidityCellValid()) {
     220             :     validity_cell =
     221      396374 :         Map::GetOrCreatePrototypeChainValidityCell(transition_map, isolate);
     222             :   }
     223             : 
     224      422551 :   if (is_dictionary_map) {
     225             :     DCHECK(!transition_map->IsJSGlobalObjectMap());
     226       39394 :     Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(0);
     227             :     // Store normal with enabled lookup on receiver.
     228             :     int config = KindBits::encode(kNormal) | LookupOnReceiverBits::encode(true);
     229       78788 :     handler->set_smi_handler(Smi::FromInt(config));
     230       39394 :     handler->set_validity_cell(*validity_cell);
     231       39394 :     return MaybeObjectHandle(handler);
     232             : 
     233             :   } else {
     234             :     // Ensure the transition map contains a valid prototype validity cell.
     235      383157 :     if (!validity_cell.is_null()) {
     236      356978 :       transition_map->set_prototype_validity_cell(*validity_cell);
     237             :     }
     238             :     return MaybeObjectHandle::Weak(transition_map);
     239             :   }
     240             : }
     241             : 
     242             : // static
     243      169757 : Handle<Object> StoreHandler::StoreThroughPrototype(
     244             :     Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
     245             :     Handle<Smi> smi_handler, MaybeObjectHandle maybe_data1,
     246             :     MaybeObjectHandle maybe_data2) {
     247             :   MaybeObjectHandle data1;
     248      169757 :   if (maybe_data1.is_null()) {
     249             :     data1 = MaybeObjectHandle::Weak(holder);
     250             :   } else {
     251       42539 :     data1 = maybe_data1;
     252             :   }
     253             : 
     254             :   int checks_count = GetPrototypeCheckCount<StoreHandler>(
     255             :       isolate, &smi_handler, receiver_map, holder, data1, maybe_data2);
     256             : 
     257             :   Handle<Object> validity_cell =
     258      169757 :       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
     259             :   DCHECK_IMPLIES(validity_cell->IsSmi(), checks_count == 0);
     260             : 
     261      169757 :   int data_count = 1 + checks_count;
     262             :   Handle<StoreHandler> handler =
     263      169757 :       isolate->factory()->NewStoreHandler(data_count);
     264             : 
     265      339514 :   handler->set_smi_handler(*smi_handler);
     266      169757 :   handler->set_validity_cell(*validity_cell);
     267             :   InitPrototypeChecks(isolate, handler, receiver_map, holder, data1,
     268             :                       maybe_data2);
     269      169757 :   return handler;
     270             : }
     271             : 
     272             : // static
     273         582 : MaybeObjectHandle StoreHandler::StoreGlobal(Handle<PropertyCell> cell) {
     274         582 :   return MaybeObjectHandle::Weak(cell);
     275             : }
     276             : 
     277             : // static
     278         371 : Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
     279             :                                         Handle<Map> receiver_map,
     280             :                                         Handle<JSProxy> proxy,
     281             :                                         Handle<JSReceiver> receiver) {
     282         371 :   Handle<Smi> smi_handler = StoreProxy(isolate);
     283         371 :   if (receiver.is_identical_to(proxy)) return smi_handler;
     284             :   return StoreThroughPrototype(isolate, receiver_map, proxy, smi_handler,
     285         207 :                                MaybeObjectHandle::Weak(proxy));
     286             : }
     287             : 
     288             : }  // namespace internal
     289      178779 : }  // namespace v8

Generated by: LCOV version 1.10