diff options
Diffstat (limited to 'deps/v8/src/prototype-inl.h')
-rw-r--r-- | deps/v8/src/prototype-inl.h | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/deps/v8/src/prototype-inl.h b/deps/v8/src/prototype-inl.h new file mode 100644 index 00000000000..820d5756f1e --- /dev/null +++ b/deps/v8/src/prototype-inl.h @@ -0,0 +1,145 @@ +// 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), + object_(nullptr), + 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), + object_(nullptr), + 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_ |