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 79268 : std::unique_ptr<debug::PropertyIterator> debug::PropertyIterator::Create(
17 : v8::Local<v8::Object> v8_object) {
18 : internal::Isolate* isolate =
19 79268 : reinterpret_cast<internal::Isolate*>(v8_object->GetIsolate());
20 : return std::unique_ptr<debug::PropertyIterator>(
21 : new internal::DebugPropertyIterator(isolate,
22 158536 : Utils::OpenHandle(*v8_object)));
23 : }
24 :
25 : namespace internal {
26 :
27 79268 : DebugPropertyIterator::DebugPropertyIterator(Isolate* isolate,
28 : Handle<JSReceiver> receiver)
29 : : isolate_(isolate),
30 : prototype_iterator_(isolate, receiver, kStartAtReceiver,
31 237804 : PrototypeIterator::END_AT_NULL) {
32 79268 : if (receiver->IsJSProxy()) {
33 20 : is_own_ = false;
34 20 : prototype_iterator_.AdvanceIgnoringProxies();
35 : }
36 79268 : if (prototype_iterator_.IsAtEnd()) return;
37 79248 : FillKeysForCurrentPrototypeAndStage();
38 79248 : if (should_move_to_next_stage()) Advance();
39 : }
40 :
41 4550501 : bool DebugPropertyIterator::Done() const {
42 4550501 : return prototype_iterator_.IsAtEnd();
43 : }
44 :
45 4550376 : void DebugPropertyIterator::Advance() {
46 4550376 : ++current_key_index_;
47 4550376 : calculated_native_accessor_flags_ = false;
48 5213512 : while (should_move_to_next_stage()) {
49 331568 : switch (stage_) {
50 : case Stage::kExoticIndices:
51 124042 : stage_ = Stage::kEnumerableStrings;
52 124042 : break;
53 : case Stage::kEnumerableStrings:
54 106134 : stage_ = Stage::kAllProperties;
55 106134 : break;
56 : case Stage::kAllProperties:
57 101392 : stage_ = kExoticIndices;
58 101392 : is_own_ = false;
59 101392 : prototype_iterator_.AdvanceIgnoringProxies();
60 101392 : break;
61 : }
62 331568 : FillKeysForCurrentPrototypeAndStage();
63 : }
64 4550376 : }
65 :
66 2995303 : bool DebugPropertyIterator::is_native_accessor() {
67 2995303 : if (stage_ == kExoticIndices) return false;
68 2993922 : CalculateNativeAccessorFlags();
69 2993922 : 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 16449688 : Handle<Name> DebugPropertyIterator::raw_name() const {
87 : DCHECK(!Done());
88 16449688 : if (stage_ == kExoticIndices) {
89 4143 : return isolate_->factory()->Uint32ToString(current_key_index_);
90 : } else {
91 : return Handle<Name>::cast(
92 32891090 : FixedArray::get(*keys_, current_key_index_, isolate_));
93 : }
94 : }
95 :
96 4471278 : v8::Local<v8::Name> DebugPropertyIterator::name() const {
97 4471278 : return Utils::ToLocal(raw_name());
98 : }
99 :
100 2995303 : v8::Maybe<v8::PropertyAttribute> DebugPropertyIterator::attributes() {
101 : Handle<JSReceiver> receiver =
102 2995303 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
103 2995303 : auto result = JSReceiver::GetPropertyAttributes(receiver, raw_name());
104 2995303 : if (result.IsNothing()) return Nothing<v8::PropertyAttribute>();
105 : DCHECK(result.FromJust() != ABSENT);
106 : return Just(static_cast<v8::PropertyAttribute>(result.FromJust()));
107 : }
108 :
109 2995283 : v8::Maybe<v8::debug::PropertyDescriptor> DebugPropertyIterator::descriptor() {
110 : Handle<JSReceiver> receiver =
111 2995283 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
112 :
113 : PropertyDescriptor descriptor;
114 : Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
115 5990566 : isolate_, receiver, raw_name(), &descriptor);
116 2995283 : 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 8985849 : });
131 : }
132 :
133 4493893 : bool DebugPropertyIterator::is_own() { return is_own_; }
134 :
135 2995283 : bool DebugPropertyIterator::is_array_index() {
136 2995283 : if (stage_ == kExoticIndices) return true;
137 2993902 : uint32_t index = 0;
138 5987804 : return raw_name()->AsArrayIndex(&index);
139 : }
140 :
141 410816 : void DebugPropertyIterator::FillKeysForCurrentPrototypeAndStage() {
142 410816 : current_key_index_ = 0;
143 410816 : exotic_length_ = 0;
144 410816 : keys_ = Handle<FixedArray>::null();
145 410816 : if (prototype_iterator_.IsAtEnd()) return;
146 : Handle<JSReceiver> receiver =
147 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
148 : bool has_exotic_indices = receiver->IsJSTypedArray();
149 354228 : if (stage_ == kExoticIndices) {
150 124052 : if (!has_exotic_indices) return;
151 : exotic_length_ = static_cast<uint32_t>(
152 123 : Handle<JSTypedArray>::cast(receiver)->length_value());
153 123 : return;
154 : }
155 : bool skip_indices = has_exotic_indices;
156 : PropertyFilter filter =
157 230176 : stage_ == kEnumerableStrings ? ENUMERABLE_STRINGS : ALL_PROPERTIES;
158 460352 : if (!KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
159 : GetKeysConversion::kConvertToString, false,
160 230176 : skip_indices)
161 : .ToHandle(&keys_)) {
162 0 : keys_ = Handle<FixedArray>::null();
163 : }
164 : }
165 :
166 4961192 : bool DebugPropertyIterator::should_move_to_next_stage() const {
167 4961192 : if (prototype_iterator_.IsAtEnd()) return false;
168 4904604 : if (stage_ == kExoticIndices) return current_key_index_ >= exotic_length_;
169 9400076 : return keys_.is_null() ||
170 9400076 : current_key_index_ >= static_cast<uint32_t>(keys_->length());
171 : }
172 :
173 : namespace {
174 2993922 : base::Flags<debug::NativeAccessorType, int> GetNativeAccessorDescriptorInternal(
175 : Handle<JSReceiver> object, Handle<Name> name) {
176 : uint32_t index;
177 2993922 : if (name->AsArrayIndex(&index)) return debug::NativeAccessorType::None;
178 : LookupIterator it =
179 2962416 : LookupIterator(object->GetIsolate(), object, name, LookupIterator::OWN);
180 2962416 : if (!it.IsFound()) return debug::NativeAccessorType::None;
181 2962416 : if (it.state() != LookupIterator::ACCESSOR) {
182 2919704 : return debug::NativeAccessorType::None;
183 : }
184 42712 : Handle<Object> structure = it.GetAccessors();
185 42712 : 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 23954 : ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */)
192 : #undef IS_BUILTIN_ACESSOR
193 : 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 2993962 : void DebugPropertyIterator::CalculateNativeAccessorFlags() {
205 2994002 : if (calculated_native_accessor_flags_) return;
206 : Handle<JSReceiver> receiver =
207 2993922 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
208 : native_accessor_flags_ =
209 5987844 : GetNativeAccessorDescriptorInternal(receiver, raw_name());
210 2993922 : calculated_native_accessor_flags_ = true;
211 : }
212 : } // namespace internal
213 120216 : } // namespace v8
|