diff options
Diffstat (limited to 'deps/v8/src/debug/debug-property-iterator.cc')
-rw-r--r-- | deps/v8/src/debug/debug-property-iterator.cc | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/deps/v8/src/debug/debug-property-iterator.cc b/deps/v8/src/debug/debug-property-iterator.cc new file mode 100644 index 0000000000..1bef58192c --- /dev/null +++ b/deps/v8/src/debug/debug-property-iterator.cc @@ -0,0 +1,213 @@ +// 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. + +#include "src/debug/debug-property-iterator.h" + +#include "src/api-inl.h" +#include "src/base/flags.h" +#include "src/keys.h" +#include "src/objects/js-array-buffer-inl.h" +#include "src/property-descriptor.h" +#include "src/property-details.h" + +namespace v8 { + +std::unique_ptr<debug::PropertyIterator> debug::PropertyIterator::Create( + v8::Local<v8::Object> v8_object) { + internal::Isolate* isolate = + reinterpret_cast<internal::Isolate*>(v8_object->GetIsolate()); + return std::unique_ptr<debug::PropertyIterator>( + new internal::DebugPropertyIterator(isolate, + Utils::OpenHandle(*v8_object))); +} + +namespace internal { + +DebugPropertyIterator::DebugPropertyIterator(Isolate* isolate, + Handle<JSReceiver> receiver) + : isolate_(isolate), + prototype_iterator_(isolate, receiver, kStartAtReceiver, + PrototypeIterator::END_AT_NULL) { + if (receiver->IsJSProxy()) { + is_own_ = false; + prototype_iterator_.AdvanceIgnoringProxies(); + } + if (prototype_iterator_.IsAtEnd()) return; + FillKeysForCurrentPrototypeAndStage(); + if (should_move_to_next_stage()) Advance(); +} + +bool DebugPropertyIterator::Done() const { + return prototype_iterator_.IsAtEnd(); +} + +void DebugPropertyIterator::Advance() { + ++current_key_index_; + calculated_native_accessor_flags_ = false; + while (should_move_to_next_stage()) { + switch (stage_) { + case Stage::kExoticIndices: + stage_ = Stage::kEnumerableStrings; + break; + case Stage::kEnumerableStrings: + stage_ = Stage::kAllProperties; + break; + case Stage::kAllProperties: + stage_ = kExoticIndices; + is_own_ = false; + prototype_iterator_.AdvanceIgnoringProxies(); + break; + } + FillKeysForCurrentPrototypeAndStage(); + } +} + +bool DebugPropertyIterator::is_native_accessor() { + if (stage_ == kExoticIndices) return false; + CalculateNativeAccessorFlags(); + return native_accessor_flags_; +} + +bool DebugPropertyIterator::has_native_getter() { + if (stage_ == kExoticIndices) return false; + CalculateNativeAccessorFlags(); + return native_accessor_flags_ & + static_cast<int>(debug::NativeAccessorType::HasGetter); +} + +bool DebugPropertyIterator::has_native_setter() { + if (stage_ == kExoticIndices) return false; + CalculateNativeAccessorFlags(); + return native_accessor_flags_ & + static_cast<int>(debug::NativeAccessorType::HasSetter); +} + +Handle<Name> DebugPropertyIterator::raw_name() const { + DCHECK(!Done()); + if (stage_ == kExoticIndices) { + return isolate_->factory()->Uint32ToString(current_key_index_); + } else { + return Handle<Name>::cast( + FixedArray::get(*keys_, current_key_index_, isolate_)); + } +} + +v8::Local<v8::Name> DebugPropertyIterator::name() const { + return Utils::ToLocal(raw_name()); +} + +v8::Maybe<v8::PropertyAttribute> DebugPropertyIterator::attributes() { + Handle<JSReceiver> receiver = + PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_); + auto result = JSReceiver::GetPropertyAttributes(receiver, raw_name()); + if (result.IsNothing()) return Nothing<v8::PropertyAttribute>(); + DCHECK(result.FromJust() != ABSENT); + return Just(static_cast<v8::PropertyAttribute>(result.FromJust())); +} + +v8::Maybe<v8::debug::PropertyDescriptor> DebugPropertyIterator::descriptor() { + Handle<JSReceiver> receiver = + PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_); + + PropertyDescriptor descriptor; + Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( + isolate_, receiver, raw_name(), &descriptor); + if (did_get_descriptor.IsNothing()) { + return Nothing<v8::debug::PropertyDescriptor>(); + } + DCHECK(did_get_descriptor.FromJust()); + return Just(v8::debug::PropertyDescriptor{ + descriptor.enumerable(), descriptor.has_enumerable(), + descriptor.configurable(), descriptor.has_configurable(), + descriptor.writable(), descriptor.has_writable(), + descriptor.has_value() ? Utils::ToLocal(descriptor.value()) + : v8::Local<v8::Value>(), + descriptor.has_get() ? Utils::ToLocal(descriptor.get()) + : v8::Local<v8::Value>(), + descriptor.has_set() ? Utils::ToLocal(descriptor.set()) + : v8::Local<v8::Value>(), + }); +} + +bool DebugPropertyIterator::is_own() { return is_own_; } + +bool DebugPropertyIterator::is_array_index() { + if (stage_ == kExoticIndices) return true; + uint32_t index = 0; + return raw_name()->AsArrayIndex(&index); +} + +void DebugPropertyIterator::FillKeysForCurrentPrototypeAndStage() { + current_key_index_ = 0; + exotic_length_ = 0; + keys_ = Handle<FixedArray>::null(); + if (prototype_iterator_.IsAtEnd()) return; + Handle<JSReceiver> receiver = + PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_); + bool has_exotic_indices = receiver->IsJSTypedArray(); + if (stage_ == kExoticIndices) { + if (!has_exotic_indices) return; + exotic_length_ = static_cast<uint32_t>( + Handle<JSTypedArray>::cast(receiver)->length_value()); + return; + } + bool skip_indices = has_exotic_indices; + PropertyFilter filter = + stage_ == kEnumerableStrings ? ENUMERABLE_STRINGS : ALL_PROPERTIES; + if (!KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter, + GetKeysConversion::kConvertToString, false, + skip_indices) + .ToHandle(&keys_)) { + keys_ = Handle<FixedArray>::null(); + } +} + +bool DebugPropertyIterator::should_move_to_next_stage() const { + if (prototype_iterator_.IsAtEnd()) return false; + if (stage_ == kExoticIndices) return current_key_index_ >= exotic_length_; + return keys_.is_null() || + current_key_index_ >= static_cast<uint32_t>(keys_->length()); +} + +namespace { +base::Flags<debug::NativeAccessorType, int> GetNativeAccessorDescriptorInternal( + Handle<JSReceiver> object, Handle<Name> name) { + uint32_t index; + if (name->AsArrayIndex(&index)) return debug::NativeAccessorType::None; + LookupIterator it = + LookupIterator(object->GetIsolate(), object, name, LookupIterator::OWN); + if (!it.IsFound()) return debug::NativeAccessorType::None; + if (it.state() != LookupIterator::ACCESSOR) { + return debug::NativeAccessorType::None; + } + Handle<Object> structure = it.GetAccessors(); + if (!structure->IsAccessorInfo()) return debug::NativeAccessorType::None; + auto isolate = object->GetIsolate(); + base::Flags<debug::NativeAccessorType, int> result; +#define IS_BUILTIN_ACESSOR(_, name, ...) \ + if (*structure == *isolate->factory()->name##_accessor()) \ + return debug::NativeAccessorType::None; + ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */) +#undef IS_BUILTIN_ACESSOR + Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure); + if (accessor_info->getter() != Object()) { + result |= debug::NativeAccessorType::HasGetter; + } + if (accessor_info->setter() != Object()) { + result |= debug::NativeAccessorType::HasSetter; + } + return result; +} +} // anonymous namespace + +void DebugPropertyIterator::CalculateNativeAccessorFlags() { + if (calculated_native_accessor_flags_) return; + Handle<JSReceiver> receiver = + PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_); + native_accessor_flags_ = + GetNativeAccessorDescriptorInternal(receiver, raw_name()); + calculated_native_accessor_flags_ = true; +} +} // namespace internal +} // namespace v8 |