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-04-26 Functions: 11 11 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             :   const int kProxyPrototypeLimit = 100 * 1000;
      31             : 
      32    24447219 :   PrototypeIterator(Isolate* isolate, Handle<JSReceiver> receiver,
      33             :                     WhereToStart where_to_start = kStartAtPrototype,
      34             :                     WhereToEnd where_to_end = END_AT_NULL)
      35             :       : isolate_(isolate),
      36             :         object_(NULL),
      37             :         handle_(receiver),
      38             :         where_to_end_(where_to_end),
      39             :         is_at_end_(false),
      40    48894438 :         seen_proxies_(0) {
      41    24447219 :     CHECK(!handle_.is_null());
      42    24447219 :     if (where_to_start == kStartAtPrototype) Advance();
      43    24447219 :   }
      44             : 
      45             :   PrototypeIterator(Isolate* isolate, JSReceiver* receiver,
      46             :                     WhereToStart where_to_start = kStartAtPrototype,
      47             :                     WhereToEnd where_to_end = END_AT_NULL)
      48             :       : isolate_(isolate),
      49             :         object_(receiver),
      50             :         where_to_end_(where_to_end),
      51             :         is_at_end_(false),
      52     3397296 :         seen_proxies_(0) {
      53     1585959 :     if (where_to_start == kStartAtPrototype) Advance();
      54             :   }
      55             : 
      56      299905 :   explicit PrototypeIterator(Map* receiver_map,
      57             :                              WhereToEnd where_to_end = END_AT_NULL)
      58             :       : isolate_(receiver_map->GetIsolate()),
      59      299905 :         object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
      60             :         where_to_end_(where_to_end),
      61      299905 :         is_at_end_(object_->IsNull(isolate_)),
      62     1499525 :         seen_proxies_(0) {
      63      299905 :     if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
      64             :       DCHECK(object_->IsJSReceiver());
      65           0 :       Map* map = JSReceiver::cast(object_)->map();
      66           0 :       is_at_end_ = !map->has_hidden_prototype();
      67             :     }
      68      299905 :   }
      69             : 
      70     5868156 :   explicit PrototypeIterator(Handle<Map> receiver_map,
      71             :                              WhereToEnd where_to_end = END_AT_NULL)
      72             :       : isolate_(receiver_map->GetIsolate()),
      73             :         object_(NULL),
      74             :         handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
      75             :                 isolate_),
      76             :         where_to_end_(where_to_end),
      77     5868156 :         is_at_end_(handle_->IsNull(isolate_)),
      78    29340780 :         seen_proxies_(0) {
      79     5868156 :     if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
      80             :       DCHECK(handle_->IsJSReceiver());
      81             :       Map* map = JSReceiver::cast(*handle_)->map();
      82       33387 :       is_at_end_ = !map->has_hidden_prototype();
      83             :     }
      84     5868156 :   }
      85             : 
      86             :   ~PrototypeIterator() {}
      87             : 
      88    10876710 :   bool HasAccess() const {
      89             :     // We can only perform access check in the handlified version of the
      90             :     // PrototypeIterator.
      91             :     DCHECK(!handle_.is_null());
      92    10876710 :     if (handle_->IsAccessCheckNeeded()) {
      93             :       return isolate_->MayAccess(handle(isolate_->context()),
      94         630 :                                  Handle<JSObject>::cast(handle_));
      95             :     }
      96             :     return true;
      97             :   }
      98             : 
      99             :   template <typename T = Object>
     100             :   T* GetCurrent() const {
     101             :     DCHECK(handle_.is_null());
     102             :     return T::cast(object_);
     103             :   }
     104             : 
     105             :   template <typename T = Object>
     106       60138 :   static Handle<T> GetCurrent(const PrototypeIterator& iterator) {
     107             :     DCHECK(!iterator.handle_.is_null());
     108             :     DCHECK(iterator.object_ == NULL);
     109       60138 :     return Handle<T>::cast(iterator.handle_);
     110             :   }
     111             : 
     112    16827315 :   void Advance() {
     113    19461064 :     if (handle_.is_null() && object_->IsJSProxy()) {
     114        1684 :       is_at_end_ = true;
     115        1684 :       object_ = isolate_->heap()->null_value();
     116        1684 :       return;
     117    31019197 :     } else if (!handle_.is_null() && handle_->IsJSProxy()) {
     118           6 :       is_at_end_ = true;
     119          12 :       handle_ = isolate_->factory()->null_value();
     120           6 :       return;
     121             :     }
     122    16825625 :     AdvanceIgnoringProxies();
     123             :   }
     124             : 
     125    38714935 :   void AdvanceIgnoringProxies() {
     126    38714935 :     Object* object = handle_.is_null() ? object_ : *handle_;
     127             :     Map* map = HeapObject::cast(object)->map();
     128             : 
     129             :     Object* prototype = map->prototype();
     130    38714935 :     is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN
     131             :                      ? !map->has_hidden_prototype()
     132    83347365 :                      : prototype->IsNull(isolate_);
     133             : 
     134    38714935 :     if (handle_.is_null()) {
     135     2651220 :       object_ = prototype;
     136             :     } else {
     137    72127430 :       handle_ = handle(prototype, isolate_);
     138             :     }
     139    38714935 :   }
     140             : 
     141             :   // Returns false iff a call to JSProxy::GetPrototype throws.
     142             :   // TODO(neis): This should probably replace Advance().
     143    10876710 :   MUST_USE_RESULT bool AdvanceFollowingProxies() {
     144             :     DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
     145    10876710 :     if (!HasAccess()) {
     146             :       // Abort the lookup if we do not have access to the current object.
     147         582 :       handle_ = isolate_->factory()->null_value();
     148         291 :       is_at_end_ = true;
     149         291 :       return true;
     150             :     }
     151    10876419 :     return AdvanceFollowingProxiesIgnoringAccessChecks();
     152             :   }
     153             : 
     154    27572585 :   MUST_USE_RESULT bool AdvanceFollowingProxiesIgnoringAccessChecks() {
     155    55145170 :     if (handle_.is_null() || !handle_->IsJSProxy()) {
     156    21870155 :       AdvanceIgnoringProxies();
     157    21870155 :       return true;
     158             :     }
     159             : 
     160             :     // Due to possible __proto__ recursion limit the number of Proxies
     161             :     // we visit to an arbitrarily chosen large number.
     162     5702430 :     seen_proxies_++;
     163     5702430 :     if (seen_proxies_ > kProxyPrototypeLimit) {
     164          57 :       isolate_->StackOverflow();
     165          57 :       return false;
     166             :     }
     167             :     MaybeHandle<Object> proto =
     168     5702373 :         JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
     169    11404746 :     if (!proto.ToHandle(&handle_)) return false;
     170             :     is_at_end_ =
     171    11403610 :         where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
     172     5702177 :     return true;
     173             :   }
     174             : 
     175       32863 :   bool IsAtEnd() const { return is_at_end_; }
     176             :   Isolate* isolate() const { return isolate_; }
     177             : 
     178             :  private:
     179             :   Isolate* isolate_;
     180             :   Object* object_;
     181             :   Handle<Object> handle_;
     182             :   WhereToEnd where_to_end_;
     183             :   bool is_at_end_;
     184             :   int seen_proxies_;
     185             : 
     186             :   DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
     187             : };
     188             : 
     189             : 
     190             : }  // namespace internal
     191             : 
     192             : }  // namespace v8
     193             : 
     194             : #endif  // V8_PROTOTYPE_H_

Generated by: LCOV version 1.10