Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/debug/debug-property-iterator.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/base/flags.h"
9 : #include "src/keys.h"
10 : #include "src/objects/js-array-buffer-inl.h"
11 : #include "src/property-descriptor.h"
12 : #include "src/property-details.h"
13 :
14 : namespace v8 {
15 :
16 79158 : std::unique_ptr<debug::PropertyIterator> debug::PropertyIterator::Create(
17 : v8::Local<v8::Object> v8_object) {
18 : internal::Isolate* isolate =
19 79158 : reinterpret_cast<internal::Isolate*>(v8_object->GetIsolate());
20 : return std::unique_ptr<debug::PropertyIterator>(
21 : new internal::DebugPropertyIterator(isolate,
22 158316 : Utils::OpenHandle(*v8_object)));
23 : }
24 :
25 : namespace internal {
26 :
27 79158 : DebugPropertyIterator::DebugPropertyIterator(Isolate* isolate,
28 : Handle<JSReceiver> receiver)
29 : : isolate_(isolate),
30 : prototype_iterator_(isolate, receiver, kStartAtReceiver,
31 237474 : PrototypeIterator::END_AT_NULL) {
32 158316 : if (receiver->IsJSProxy()) {
33 15 : is_own_ = false;
34 15 : prototype_iterator_.AdvanceIgnoringProxies();
35 : }
36 158316 : if (prototype_iterator_.IsAtEnd()) return;
37 79143 : FillKeysForCurrentPrototypeAndStage();
38 79143 : if (should_move_to_next_stage()) Advance();
39 : }
40 :
41 4548691 : bool DebugPropertyIterator::Done() const {
42 4548691 : return prototype_iterator_.IsAtEnd();
43 : }
44 :
45 4548591 : void DebugPropertyIterator::Advance() {
46 4548591 : ++current_key_index_;
47 4548591 : calculated_native_accessor_flags_ = false;
48 9428145 : while (should_move_to_next_stage()) {
49 330963 : switch (stage_) {
50 : case Stage::kExoticIndices:
51 123812 : stage_ = Stage::kEnumerableStrings;
52 123812 : break;
53 : case Stage::kEnumerableStrings:
54 105904 : stage_ = Stage::kAllProperties;
55 105904 : break;
56 : case Stage::kAllProperties:
57 101247 : stage_ = kExoticIndices;
58 101247 : is_own_ = false;
59 101247 : prototype_iterator_.AdvanceIgnoringProxies();
60 101247 : break;
61 : }
62 330963 : FillKeysForCurrentPrototypeAndStage();
63 : }
64 4548591 : }
65 :
66 2993733 : bool DebugPropertyIterator::is_native_accessor() {
67 2993733 : if (stage_ == kExoticIndices) return false;
68 2992462 : CalculateNativeAccessorFlags();
69 2992462 : return native_accessor_flags_;
70 : }
71 :
72 20 : bool DebugPropertyIterator::has_native_getter() {
73 20 : if (stage_ == kExoticIndices) return false;
74 20 : CalculateNativeAccessorFlags();
75 20 : return native_accessor_flags_ &
76 20 : static_cast<int>(debug::NativeAccessorType::HasGetter);
77 : }
78 :
79 20 : bool DebugPropertyIterator::has_native_setter() {
80 20 : if (stage_ == kExoticIndices) return false;
81 20 : CalculateNativeAccessorFlags();
82 20 : return native_accessor_flags_ &
83 20 : static_cast<int>(debug::NativeAccessorType::HasSetter);
84 : }
85 :
86 16441938 : Handle<Name> DebugPropertyIterator::raw_name() const {
87 : DCHECK(!Done());
88 16441938 : if (stage_ == kExoticIndices) {
89 3813 : return isolate_->factory()->Uint32ToString(current_key_index_);
90 : } else {
91 : return Handle<Name>::cast(
92 32876250 : FixedArray::get(*keys_, current_key_index_, isolate_));
93 : }
94 : }
95 :
96 4469578 : v8::Local<v8::Name> DebugPropertyIterator::name() const {
97 4469578 : return Utils::ToLocal(raw_name());
98 : }
99 :
100 2993733 : v8::Maybe<v8::PropertyAttribute> DebugPropertyIterator::attributes() {
101 : Handle<JSReceiver> receiver =
102 2993733 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
103 2993733 : auto result = JSReceiver::GetPropertyAttributes(receiver, raw_name());
104 2993733 : if (result.IsNothing()) return Nothing<v8::PropertyAttribute>();
105 : DCHECK(result.FromJust() != ABSENT);
106 : return Just(static_cast<v8::PropertyAttribute>(result.FromJust()));
107 : }
108 :
109 2993713 : v8::Maybe<v8::debug::PropertyDescriptor> DebugPropertyIterator::descriptor() {
110 : Handle<JSReceiver> receiver =
111 2993713 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
112 :
113 : PropertyDescriptor descriptor;
114 : Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
115 5987426 : isolate_, receiver, raw_name(), &descriptor);
116 2993713 : if (did_get_descriptor.IsNothing()) {
117 : return Nothing<v8::debug::PropertyDescriptor>();
118 : }
119 : DCHECK(did_get_descriptor.FromJust());
120 : return Just(v8::debug::PropertyDescriptor{
121 : descriptor.enumerable(), descriptor.has_enumerable(),
122 : descriptor.configurable(), descriptor.has_configurable(),
123 : descriptor.writable(), descriptor.has_writable(),
124 : descriptor.has_value() ? Utils::ToLocal(descriptor.value())
125 : : v8::Local<v8::Value>(),
126 : descriptor.has_get() ? Utils::ToLocal(descriptor.get())
127 : : v8::Local<v8::Value>(),
128 : descriptor.has_set() ? Utils::ToLocal(descriptor.set())
129 : : v8::Local<v8::Value>(),
130 8981139 : });
131 : }
132 :
133 4492108 : bool DebugPropertyIterator::is_own() { return is_own_; }
134 :
135 2993723 : bool DebugPropertyIterator::is_array_index() {
136 2993723 : if (stage_ == kExoticIndices) return true;
137 2992452 : uint32_t index = 0;
138 5984904 : return raw_name()->AsArrayIndex(&index);
139 : }
140 :
141 410106 : void DebugPropertyIterator::FillKeysForCurrentPrototypeAndStage() {
142 410106 : current_key_index_ = 0;
143 410106 : exotic_length_ = 0;
144 410106 : keys_ = Handle<FixedArray>::null();
145 410106 : if (prototype_iterator_.IsAtEnd()) return;
146 : Handle<JSReceiver> receiver =
147 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
148 707076 : bool has_exotic_indices = receiver->IsJSTypedArray();
149 353538 : if (stage_ == kExoticIndices) {
150 123822 : if (!has_exotic_indices) return;
151 : exotic_length_ = static_cast<uint32_t>(
152 206 : Handle<JSTypedArray>::cast(receiver)->length_value());
153 103 : return;
154 : }
155 : bool skip_indices = has_exotic_indices;
156 : PropertyFilter filter =
157 229716 : stage_ == kEnumerableStrings ? ENUMERABLE_STRINGS : ALL_PROPERTIES;
158 229716 : if (!KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
159 : GetKeysConversion::kConvertToString, false,
160 229716 : skip_indices)
161 689148 : .ToHandle(&keys_)) {
162 0 : keys_ = Handle<FixedArray>::null();
163 : }
164 : }
165 :
166 4958697 : bool DebugPropertyIterator::should_move_to_next_stage() const {
167 4958697 : if (prototype_iterator_.IsAtEnd()) return false;
168 4902129 : if (stage_ == kExoticIndices) return current_key_index_ >= exotic_length_;
169 9395976 : return keys_.is_null() ||
170 14093964 : current_key_index_ >= static_cast<uint32_t>(keys_->length());
171 : }
172 :
173 : namespace {
174 2992462 : base::Flags<debug::NativeAccessorType, int> GetNativeAccessorDescriptorInternal(
175 : Handle<JSReceiver> object, Handle<Name> name) {
176 : uint32_t index;
177 2992462 : if (name->AsArrayIndex(&index)) return debug::NativeAccessorType::None;
178 : LookupIterator it =
179 2960986 : LookupIterator(object->GetIsolate(), object, name, LookupIterator::OWN);
180 2960986 : if (!it.IsFound()) return debug::NativeAccessorType::None;
181 2960986 : if (it.state() != LookupIterator::ACCESSOR) {
182 2919449 : return debug::NativeAccessorType::None;
183 : }
184 41537 : Handle<Object> structure = it.GetAccessors();
185 83074 : if (!structure->IsAccessorInfo()) return debug::NativeAccessorType::None;
186 : auto isolate = object->GetIsolate();
187 : base::Flags<debug::NativeAccessorType, int> result;
188 : #define IS_BUILTIN_ACESSOR(_, name, ...) \
189 : if (*structure == *isolate->factory()->name##_accessor()) \
190 : return debug::NativeAccessorType::None;
191 23899 : ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */)
192 : #undef IS_BUILTIN_ACESSOR
193 20 : Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
194 20 : if (accessor_info->getter() != Object()) {
195 : result |= debug::NativeAccessorType::HasGetter;
196 : }
197 20 : if (accessor_info->setter() != Object()) {
198 : result |= debug::NativeAccessorType::HasSetter;
199 : }
200 20 : return result;
201 : }
202 : } // anonymous namespace
203 :
204 2992502 : void DebugPropertyIterator::CalculateNativeAccessorFlags() {
205 2992542 : if (calculated_native_accessor_flags_) return;
206 : Handle<JSReceiver> receiver =
207 2992462 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
208 5984924 : native_accessor_flags_ =
209 5984924 : GetNativeAccessorDescriptorInternal(receiver, raw_name());
210 2992462 : calculated_native_accessor_flags_ = true;
211 : }
212 : } // namespace internal
213 178779 : } // namespace v8
|