| Index: src/prototype-iterator.h
|
| diff --git a/src/prototype-iterator.h b/src/prototype-iterator.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bf56947a6b6c395b3cb755b1d0c9dab81467636a
|
| --- /dev/null
|
| +++ b/src/prototype-iterator.h
|
| @@ -0,0 +1,291 @@
|
| +// Copyright 2014 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_ITERATOR_H_
|
| +#define V8_PROTOTYPE_ITERATOR_H_
|
| +
|
| +// This file defines an iterator that should be used to iterate over an
|
| +// object's prototype chain. The iterator template can be specialized to
|
| +// handle all common variations of iterating over the prototype chain,
|
| +// and at the same time makes sure that security interceptors are honored.
|
| +//
|
| +// The iterator can also be used to look up just the prototype.
|
| +//
|
| +// The iterator should always be used unless it is safe to skip the security
|
| +// interceptors, e.g., when all objects on the prototype chain are from the
|
| +// same context.
|
| +
|
| +#include "src/v8.h"
|
| +
|
| +#include "src/base/macros.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +/**
|
| + * Whether to walk the prototype chain based on the map, or by using a switch
|
| + * over the type. The latter will also work for non-JSReceiver prototypes but
|
| + * is more expensive.
|
| + */
|
| +enum WalkType { MAP_BASED_WALK, TYPE_BASED_WALK };
|
| +
|
| +
|
| +/**
|
| + * Where to stop the chain walk: either at the null value, a given object, or
|
| + * the first non-hidden prototype.
|
| + */
|
| +enum WhereToEnd { END_AT_NULL_VALUE, END_AT_GIVEN_OBJECT, END_AT_NON_HIDDEN };
|
| +
|
| +
|
| +/**
|
| + * How the iterator stores the object.
|
| + */
|
| +enum StorageType { STORE_AS_POINTER, STORE_AS_HANDLE };
|
| +
|
| +
|
| +template <int storage_type>
|
| +struct ObjectStorageType;
|
| +
|
| +
|
| +template <>
|
| +struct ObjectStorageType<STORE_AS_POINTER> {
|
| + typedef Object* storage_type;
|
| +};
|
| +
|
| +
|
| +template <>
|
| +struct ObjectStorageType<STORE_AS_HANDLE> {
|
| + typedef Handle<Object> storage_type;
|
| +};
|
| +
|
| +template <int store_as, int type_of_walk, int where_to_end>
|
| +class PrototypeIterator;
|
| +
|
| +
|
| +template <int store_as, int where_to_end>
|
| +class PrototypeIterator<store_as, TYPE_BASED_WALK, where_to_end> {
|
| + public:
|
| + typedef typename ObjectStorageType<store_as>::storage_type storage_type;
|
| +
|
| + PrototypeIterator(Isolate* isolate, storage_type object)
|
| + : isolate_(isolate), object_(object) {}
|
| + ~PrototypeIterator() {}
|
| +
|
| + bool IsAtEnd();
|
| + PrototypeIterator& Advance();
|
| +
|
| + storage_type GetCurrent() const { return object_; }
|
| +
|
| + private:
|
| + Isolate* isolate_;
|
| + storage_type object_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
|
| +};
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK,
|
| + END_AT_NULL_VALUE>::IsAtEnd() {
|
| + return object_->IsNull();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK,
|
| + END_AT_NULL_VALUE>::IsAtEnd() {
|
| + return object_->IsNull();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::IsAtEnd() {
|
| + return !object_->IsJSReceiver() ||
|
| + !JSReceiver::cast(object_)->map()->is_hidden_prototype();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::IsAtEnd() {
|
| + return !object_->IsJSReceiver() ||
|
| + !Handle<JSReceiver>::cast(object_)->map()->is_hidden_prototype();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE
|
| +PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, END_AT_NULL_VALUE>&
|
| +PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK,
|
| + END_AT_NULL_VALUE>::Advance() {
|
| + object_ = object_->GetPrototype(isolate_);
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE
|
| +PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, END_AT_NULL_VALUE>&
|
| +PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK,
|
| + END_AT_NULL_VALUE>::Advance() {
|
| + object_ = Object::GetPrototype(isolate_, object_);
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE
|
| +PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK, END_AT_NON_HIDDEN>&
|
| +PrototypeIterator<STORE_AS_POINTER, TYPE_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::Advance() {
|
| + object_ = object_->GetPrototype(isolate_);
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE
|
| +PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, END_AT_NON_HIDDEN>&
|
| +PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::Advance() {
|
| + object_ = Object::GetPrototype(isolate_, object_);
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +template <>
|
| +class PrototypeIterator<STORE_AS_HANDLE, TYPE_BASED_WALK, END_AT_GIVEN_OBJECT> {
|
| + public:
|
| + PrototypeIterator(Isolate* isolate, Handle<Object> object, Handle<Object> end)
|
| + : isolate_(isolate), object_(object), end_(end) {}
|
| + ~PrototypeIterator() {}
|
| +
|
| + bool IsAtEnd() { return object_->IsNull() || *object_ == *end_; }
|
| +
|
| + PrototypeIterator& Advance() {
|
| + object_ = Object::GetPrototype(isolate_, object_);
|
| + return *this;
|
| + }
|
| +
|
| + Handle<Object> GetCurrent() const { return object_; }
|
| +
|
| + private:
|
| + Isolate* isolate_;
|
| + Handle<Object> object_;
|
| + Handle<Object> end_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
|
| +};
|
| +
|
| +
|
| +template <int store_as, int where_to_end>
|
| +class PrototypeIterator<store_as, MAP_BASED_WALK, where_to_end> {
|
| + public:
|
| + typedef typename ObjectStorageType<store_as>::storage_type storage_type;
|
| +
|
| + explicit PrototypeIterator(storage_type receiver) : object_(receiver) {}
|
| + ~PrototypeIterator() {}
|
| +
|
| + bool IsAtEnd();
|
| +
|
| + PrototypeIterator& Advance();
|
| +
|
| + storage_type GetCurrent() const { return object_; }
|
| +
|
| + private:
|
| + storage_type object_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
|
| +};
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK,
|
| + END_AT_NULL_VALUE>::IsAtEnd() {
|
| + return object_->IsNull();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK,
|
| + END_AT_NULL_VALUE>::IsAtEnd() {
|
| + return object_->IsNull();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::IsAtEnd() {
|
| + return !object_->IsJSReceiver() ||
|
| + !JSReceiver::cast(object_)->map()->is_hidden_prototype();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE bool PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::IsAtEnd() {
|
| + return !object_->IsJSReceiver() ||
|
| + !Handle<JSReceiver>::cast(object_)->map()->is_hidden_prototype();
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE
|
| +PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, END_AT_NULL_VALUE>&
|
| +PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK,
|
| + END_AT_NULL_VALUE>::Advance() {
|
| + object_ = JSReceiver::cast(object_)->GetPrototype();
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, END_AT_NULL_VALUE>&
|
| +PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK,
|
| + END_AT_NULL_VALUE>::Advance() {
|
| + object_ = handle(Handle<JSReceiver>::cast(object_)->GetPrototype(),
|
| + Handle<JSReceiver>::cast(object_)->GetIsolate());
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE
|
| +PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK, END_AT_NON_HIDDEN>&
|
| +PrototypeIterator<STORE_AS_POINTER, MAP_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::Advance() {
|
| + object_ = JSReceiver::cast(object_)->GetPrototype();
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +template <>
|
| +V8_INLINE PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK, END_AT_NON_HIDDEN>&
|
| +PrototypeIterator<STORE_AS_HANDLE, MAP_BASED_WALK,
|
| + END_AT_NON_HIDDEN>::Advance() {
|
| + object_ = handle(Handle<JSReceiver>::cast(object_)->GetPrototype(),
|
| + Handle<JSReceiver>::cast(object_)->GetIsolate());
|
| + return *this;
|
| +}
|
| +
|
| +
|
| +#define SAFE_GET_PROTOTYPE(isolate, object) \
|
| + v8::internal::PrototypeIterator< \
|
| + v8::internal::STORE_AS_POINTER, v8::internal::TYPE_BASED_WALK, \
|
| + v8::internal::END_AT_NULL_VALUE>(isolate, object) \
|
| + .Advance() \
|
| + .GetCurrent()
|
| +
|
| +
|
| +#define SAFE_GET_PROTOTYPE_FAST(receiver) \
|
| + v8::internal::PrototypeIterator<v8::internal::STORE_AS_POINTER, \
|
| + v8::internal::MAP_BASED_WALK, \
|
| + v8::internal::END_AT_NULL_VALUE>(receiver) \
|
| + .Advance() \
|
| + .GetCurrent()
|
| +}
|
| +} // namespace v8::internal
|
| +
|
| +#endif // V8_PROTOTYPE_ITERATOR_H_
|
|
|