056f927861
Tbr: ahaas@chromium.org,leszeks@chromium.org,verwaest@chromium.org Bug: v8:3770 Change-Id: Ia6530fbb70dac05e9972283781c3550d8b50e1eb Reviewed-on: https://chromium-review.googlesource.com/c/1390116 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Alexei Filippov <alph@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#58470}
144 lines
4.5 KiB
C++
144 lines
4.5 KiB
C++
// 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.
|
|
|
|
#ifndef V8_PROTOTYPE_INL_H_
|
|
#define V8_PROTOTYPE_INL_H_
|
|
|
|
#include "src/prototype.h"
|
|
|
|
#include "src/handles-inl.h"
|
|
#include "src/objects/map-inl.h"
|
|
|
|
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();
|
|
}
|
|
|
|
PrototypeIterator::PrototypeIterator(Isolate* isolate, JSReceiver receiver,
|
|
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();
|
|
}
|
|
|
|
PrototypeIterator::PrototypeIterator(Isolate* isolate, Map receiver_map,
|
|
WhereToEnd where_to_end)
|
|
: isolate_(isolate),
|
|
object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
|
|
where_to_end_(where_to_end),
|
|
is_at_end_(object_->IsNull(isolate_)),
|
|
seen_proxies_(0) {
|
|
if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
|
|
DCHECK(object_->IsJSReceiver());
|
|
Map map = JSReceiver::cast(object_)->map();
|
|
is_at_end_ = !map->has_hidden_prototype();
|
|
}
|
|
}
|
|
|
|
PrototypeIterator::PrototypeIterator(Isolate* isolate, Handle<Map> receiver_map,
|
|
WhereToEnd where_to_end)
|
|
: isolate_(isolate),
|
|
handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
|
|
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());
|
|
Map map = JSReceiver::cast(*handle_)->map();
|
|
is_at_end_ = !map->has_hidden_prototype();
|
|
}
|
|
}
|
|
|
|
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() {
|
|
if (handle_.is_null() && object_->IsJSProxy()) {
|
|
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() {
|
|
Object object = handle_.is_null() ? object_ : *handle_;
|
|
Map map = HeapObject::cast(object)->map();
|
|
|
|
Object prototype = map->prototype();
|
|
is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN ? !map->has_hidden_prototype()
|
|
: prototype->IsNull(isolate_);
|
|
|
|
if (handle_.is_null()) {
|
|
object_ = prototype;
|
|
} else {
|
|
handle_ = handle(prototype, isolate_);
|
|
}
|
|
}
|
|
|
|
V8_WARN_UNUSED_RESULT bool PrototypeIterator::AdvanceFollowingProxies() {
|
|
DCHECK(!(handle_.is_null() && object_->IsJSProxy()));
|
|
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;
|
|
}
|
|
MaybeHandle<Object> proto =
|
|
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
|
|
|
|
#endif // V8_PROTOTYPE_INL_H_
|