LCOV - code coverage report
Current view: top level - src - prototype.h (source / functions) Hit Total Coverage
Test: app.info Lines: 61 63 96.8 %
Date: 2017-10-20 Functions: 10 10 100.0 %

          Line data    Source code
       1             : // Copyright 2014 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             : #ifndef V8_PROTOTYPE_H_
       6             : #define V8_PROTOTYPE_H_
       7             : 
       8             : #include "src/isolate.h"
       9             : #include "src/objects.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : /**
      15             :  * A class to uniformly access the prototype of any Object and walk its
      16             :  * prototype chain.
      17             :  *
      18             :  * The PrototypeIterator can either start at the prototype (default), or
      19             :  * include the receiver itself. If a PrototypeIterator is constructed for a
      20             :  * Map, it will always start at the prototype.
      21             :  *
      22             :  * The PrototypeIterator can either run to the null_value(), the first
      23             :  * non-hidden prototype, or a given object.
      24             :  */
      25             : 
      26             : class PrototypeIterator {
      27             :  public:
      28             :   enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN };
      29             : 
      30    13340210 :   PrototypeIterator(Isolate* isolate, Handle<JSReceiver> receiver,
      31             :                     WhereToStart where_to_start = kStartAtPrototype,
      32             :                     WhereToEnd where_to_end = END_AT_NULL)
      33             :       : isolate_(isolate),
      34             :         object_(nullptr),
      35             :         handle_(receiver),
      36             :         where_to_end_(where_to_end),
      37             :         is_at_end_(false),
      38    26680420 :         seen_proxies_(0) {
      39    13340210 :     CHECK(!handle_.is_null());
      40    13340210 :     if (where_to_start == kStartAtPrototype) Advance();
      41    13340210 :   }
      42             : 
      43             :   PrototypeIterator(Isolate* isolate, JSReceiver* receiver,
      44             :                     WhereToStart where_to_start = kStartAtPrototype,
      45             :                     WhereToEnd where_to_end = END_AT_NULL)
      46             :       : isolate_(isolate),
      47             :         object_(receiver),
      48             :         where_to_end_(where_to_end),
      49             :         is_at_end_(false),
      50     2318466 :         seen_proxies_(0) {
      51      954424 :     if (where_to_start == kStartAtPrototype) Advance();
      52             :   }
      53             : 
      54      172253 :   explicit PrototypeIterator(Map* receiver_map,
      55             :                              WhereToEnd where_to_end = END_AT_NULL)
      56             :       : isolate_(receiver_map->GetIsolate()),
      57      172253 :         object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
      58             :         where_to_end_(where_to_end),
      59      172253 :         is_at_end_(object_->IsNull(isolate_)),
      60      689012 :         seen_proxies_(0) {
      61      172253 :     if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
      62             :       DCHECK(object_->IsJSReceiver());
      63           0 :       Map* map = JSReceiver::cast(object_)->map();
      64           0 :       is_at_end_ = !map->has_hidden_prototype();
      65             :     }
      66      172253 :   }
      67             : 
      68     2003796 :   explicit PrototypeIterator(Handle<Map> receiver_map,
      69             :                              WhereToEnd where_to_end = END_AT_NULL)
      70             :       : isolate_(receiver_map->GetIsolate()),
      71             :         object_(nullptr),
      72             :         handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
      73             :                 isolate_),
      74             :         where_to_end_(where_to_end),
      75     2003796 :         is_at_end_(handle_->IsNull(isolate_)),
      76     8015184 :         seen_proxies_(0) {
      77     2003796 :     if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
      78             :       DCHECK(handle_->IsJSReceiver());
      79             :       Map* map = JSReceiver::cast(*handle_)->map();
      80       10684 :       is_at_end_ = !map->has_hidden_prototype();
      81             :     }
      82     2003796 :   }
      83             : 
      84             :   ~PrototypeIterator() {}
      85             : 
      86     7246831 :   bool HasAccess() const {
      87             :     // We can only perform access check in the handlified version of the
      88             :     // PrototypeIterator.
      89             :     DCHECK(!handle_.is_null());
      90     7246831 :     if (handle_->IsAccessCheckNeeded()) {
      91             :       return isolate_->MayAccess(handle(isolate_->context()),
      92         426 :                                  Handle<JSObject>::cast(handle_));
      93             :     }
      94             :     return true;
      95             :   }
      96             : 
      97             :   template <typename T = Object>
      98             :   T* GetCurrent() const {
      99             :     DCHECK(handle_.is_null());
     100             :     return T::cast(object_);
     101             :   }
     102             : 
     103             :   template <typename T = Object>
     104       16583 :   static Handle<T> GetCurrent(const PrototypeIterator& iterator) {
     105             :     DCHECK(!iterator.handle_.is_null());
     106             :     DCHECK_NULL(iterator.object_);
     107       16583 :     return Handle<T>::cast(iterator.handle_);
     108             :   }
     109             : 
     110     8379633 :   void Advance() {
     111    10238095 :     if (handle_.is_null() && object_->IsJSProxy()) {
     112        1238 :       is_at_end_ = true;
     113        1238 :       object_ = isolate_->heap()->null_value();
     114        1238 :       return;
     115    14899568 :     } else if (!handle_.is_null() && handle_->IsJSProxy()) {
     116         177 :       is_at_end_ = true;
     117         354 :       handle_ = isolate_->factory()->null_value();
     118         177 :       return;
     119             :     }
     120     8378218 :     AdvanceIgnoringProxies();
     121             :   }
     122             : 
     123    21126853 :   void AdvanceIgnoringProxies() {
     124    21126853 :     Object* object = handle_.is_null() ? object_ : *handle_;
     125             :     Map* map = HeapObject::cast(object)->map();
     126             : 
     127             :     Object* prototype = map->prototype();
     128    21126853 :     is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN
     129             :                      ? !map->has_hidden_prototype()
     130    46086774 :                      : prototype->IsNull(isolate_);
     131             : 
     132    21126853 :     if (handle_.is_null()) {
     133     1870525 :       object_ = prototype;
     134             :     } else {
     135    38512655 :       handle_ = handle(prototype, isolate_);
     136             :     }
     137    21126852 :   }
     138             : 
     139             :   // Returns false iff a call to JSProxy::GetPrototype throws.
     140             :   // TODO(neis): This should probably replace Advance().
     141     7246831 :   MUST_USE_RESULT bool AdvanceFollowingProxies() {
     142             :     DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
     143     7246831 :     if (!HasAccess()) {
     144             :       // Abort the lookup if we do not have access to the current object.
     145         386 :       handle_ = isolate_->factory()->null_value();
     146         193 :       is_at_end_ = true;
     147         193 :       return true;
     148             :     }
     149     7246638 :     return AdvanceFollowingProxiesIgnoringAccessChecks();
     150             :   }
     151             : 
     152    16525754 :   MUST_USE_RESULT bool AdvanceFollowingProxiesIgnoringAccessChecks() {
     153    33051508 :     if (handle_.is_null() || !handle_->IsJSProxy()) {
     154    12735332 :       AdvanceIgnoringProxies();
     155    12735332 :       return true;
     156             :     }
     157             : 
     158             :     // Due to possible __proto__ recursion limit the number of Proxies
     159             :     // we visit to an arbitrarily chosen large number.
     160     3790422 :     seen_proxies_++;
     161     3790422 :     if (seen_proxies_ > JSProxy::kMaxIterationLimit) {
     162          37 :       isolate_->StackOverflow();
     163          37 :       return false;
     164             :     }
     165             :     MaybeHandle<Object> proto =
     166     3790385 :         JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
     167     7580770 :     if (!proto.ToHandle(&handle_)) return false;
     168             :     is_at_end_ =
     169     7580030 :         where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
     170     3790259 :     return true;
     171             :   }
     172             : 
     173       22144 :   bool IsAtEnd() const { return is_at_end_; }
     174             :   Isolate* isolate() const { return isolate_; }
     175             : 
     176             :  private:
     177             :   Isolate* isolate_;
     178             :   Object* object_;
     179             :   Handle<Object> handle_;
     180             :   WhereToEnd where_to_end_;
     181             :   bool is_at_end_;
     182             :   int seen_proxies_;
     183             : 
     184             :   DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
     185             : };
     186             : 
     187             : 
     188             : }  // namespace internal
     189             : 
     190             : }  // namespace v8
     191             : 
     192             : #endif  // V8_PROTOTYPE_H_

Generated by: LCOV version 1.10