prototype-inl.h 4.57 KB
Newer Older
1 2 3 4
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_OBJECTS_PROTOTYPE_INL_H_
#define V8_OBJECTS_PROTOTYPE_INL_H_
7

8
#include "src/objects/prototype.h"
9

10
#include "src/handles/handles-inl.h"
11
#include "src/objects/js-proxy.h"
12 13
#include "src/objects/map-inl.h"

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
namespace v8 {
namespace internal {

PrototypeIterator::PrototypeIterator(Isolate* isolate,
                                     Handle<JSReceiver> receiver,
                                     WhereToStart where_to_start,
                                     WhereToEnd where_to_end)
    : isolate_(isolate),
      handle_(receiver),
      where_to_end_(where_to_end),
      is_at_end_(false),
      seen_proxies_(0) {
  CHECK(!handle_.is_null());
  if (where_to_start == kStartAtPrototype) Advance();
}

30
PrototypeIterator::PrototypeIterator(Isolate* isolate, JSReceiver receiver,
31 32 33 34 35 36 37 38 39 40
                                     WhereToStart where_to_start,
                                     WhereToEnd where_to_end)
    : isolate_(isolate),
      object_(receiver),
      where_to_end_(where_to_end),
      is_at_end_(false),
      seen_proxies_(0) {
  if (where_to_start == kStartAtPrototype) Advance();
}

41
PrototypeIterator::PrototypeIterator(Isolate* isolate, Map receiver_map,
42 43
                                     WhereToEnd where_to_end)
    : isolate_(isolate),
44
      object_(receiver_map.GetPrototypeChainRootMap(isolate_).prototype()),
45
      where_to_end_(where_to_end),
46
      is_at_end_(object_.IsNull(isolate_)),
47 48
      seen_proxies_(0) {
  if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
49 50
    DCHECK(object_.IsJSReceiver());
    Map map = JSReceiver::cast(object_).map();
51
    is_at_end_ = !map.IsJSGlobalProxyMap();
52 53 54 55 56 57
  }
}

PrototypeIterator::PrototypeIterator(Isolate* isolate, Handle<Map> receiver_map,
                                     WhereToEnd where_to_end)
    : isolate_(isolate),
58
      handle_(receiver_map->GetPrototypeChainRootMap(isolate_).prototype(),
59 60 61 62 63 64
              isolate_),
      where_to_end_(where_to_end),
      is_at_end_(handle_->IsNull(isolate_)),
      seen_proxies_(0) {
  if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
    DCHECK(handle_->IsJSReceiver());
65
    Map map = JSReceiver::cast(*handle_).map();
66
    is_at_end_ = !map.IsJSGlobalProxyMap();
67 68 69
  }
}

70 71 72 73 74 75 76 77 78 79 80 81
bool PrototypeIterator::HasAccess() const {
  // We can only perform access check in the handlified version of the
  // PrototypeIterator.
  DCHECK(!handle_.is_null());
  if (handle_->IsAccessCheckNeeded()) {
    return isolate_->MayAccess(handle(isolate_->context(), isolate_),
                               Handle<JSObject>::cast(handle_));
  }
  return true;
}

void PrototypeIterator::Advance() {
82
  if (handle_.is_null() && object_.IsJSProxy()) {
83 84 85 86 87 88 89 90 91 92 93 94
    is_at_end_ = true;
    object_ = ReadOnlyRoots(isolate_).null_value();
    return;
  } else if (!handle_.is_null() && handle_->IsJSProxy()) {
    is_at_end_ = true;
    handle_ = isolate_->factory()->null_value();
    return;
  }
  AdvanceIgnoringProxies();
}

void PrototypeIterator::AdvanceIgnoringProxies() {
95
  Object object = handle_.is_null() ? object_ : *handle_;
96
  Map map = HeapObject::cast(object).map();
97

98
  HeapObject prototype = map.prototype();
99 100 101
  is_at_end_ =
      prototype.IsNull(isolate_) ||
      (where_to_end_ == END_AT_NON_HIDDEN && !map.IsJSGlobalProxyMap());
102 103 104 105 106 107 108 109 110

  if (handle_.is_null()) {
    object_ = prototype;
  } else {
    handle_ = handle(prototype, isolate_);
  }
}

V8_WARN_UNUSED_RESULT bool PrototypeIterator::AdvanceFollowingProxies() {
111
  DCHECK(!(handle_.is_null() && object_.IsJSProxy()));
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
  if (!HasAccess()) {
    // Abort the lookup if we do not have access to the current object.
    handle_ = isolate_->factory()->null_value();
    is_at_end_ = true;
    return true;
  }
  return AdvanceFollowingProxiesIgnoringAccessChecks();
}

V8_WARN_UNUSED_RESULT bool
PrototypeIterator::AdvanceFollowingProxiesIgnoringAccessChecks() {
  if (handle_.is_null() || !handle_->IsJSProxy()) {
    AdvanceIgnoringProxies();
    return true;
  }

  // Due to possible __proto__ recursion limit the number of Proxies
  // we visit to an arbitrarily chosen large number.
  seen_proxies_++;
  if (seen_proxies_ > JSProxy::kMaxIterationLimit) {
    isolate_->StackOverflow();
    return false;
  }
135
  MaybeHandle<HeapObject> proto =
136 137 138 139 140 141 142 143 144
      JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
  if (!proto.ToHandle(&handle_)) return false;
  is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN || handle_->IsNull(isolate_);
  return true;
}

}  // namespace internal
}  // namespace v8

145
#endif  // V8_OBJECTS_PROTOTYPE_INL_H_