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 : // TODO(bmeurer, v8:4153): Change this to size_t later.
152 : exotic_length_ =
153 123 : static_cast<uint32_t>(Handle<JSTypedArray>::cast(receiver)->length());
154 123 : return;
155 : }
156 : bool skip_indices = has_exotic_indices;
157 : PropertyFilter filter =
158 230176 : stage_ == kEnumerableStrings ? ENUMERABLE_STRINGS : ALL_PROPERTIES;
159 460352 : if (!KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
160 : GetKeysConversion::kConvertToString, false,
161 230176 : skip_indices)
162 : .ToHandle(&keys_)) {
163 0 : keys_ = Handle<FixedArray>::null();
164 : }
165 : }
166 :
167 0 : bool DebugPropertyIterator::should_move_to_next_stage() const {
168 4961192 : if (prototype_iterator_.IsAtEnd()) return false;
169 4904604 : if (stage_ == kExoticIndices) return current_key_index_ >= exotic_length_;
170 9400076 : return keys_.is_null() ||
171 9400076 : current_key_index_ >= static_cast<uint32_t>(keys_->length());
172 : }
173 :
174 : namespace {
175 2993922 : base::Flags<debug::NativeAccessorType, int> GetNativeAccessorDescriptorInternal(
176 : Handle<JSReceiver> object, Handle<Name> name) {
177 : uint32_t index;
178 2993922 : if (name->AsArrayIndex(&index)) return debug::NativeAccessorType::None;
179 : LookupIterator it =
180 2962416 : LookupIterator(object->GetIsolate(), object, name, LookupIterator::OWN);
181 2962416 : if (!it.IsFound()) return debug::NativeAccessorType::None;
182 2962416 : if (it.state() != LookupIterator::ACCESSOR) {
183 2919477 : return debug::NativeAccessorType::None;
184 : }
185 42939 : Handle<Object> structure = it.GetAccessors();
186 42939 : if (!structure->IsAccessorInfo()) return debug::NativeAccessorType::None;
187 : auto isolate = object->GetIsolate();
188 : base::Flags<debug::NativeAccessorType, int> result;
189 : #define IS_BUILTIN_ACESSOR(_, name, ...) \
190 : if (*structure == *isolate->factory()->name##_accessor()) \
191 : return debug::NativeAccessorType::None;
192 25089 : ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */)
193 : #undef IS_BUILTIN_ACESSOR
194 : Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
195 20 : if (accessor_info->getter() != Object()) {
196 : result |= debug::NativeAccessorType::HasGetter;
197 : }
198 20 : if (accessor_info->setter() != Object()) {
199 : result |= debug::NativeAccessorType::HasSetter;
200 : }
201 20 : return result;
202 : }
203 : } // anonymous namespace
204 :
205 2993962 : void DebugPropertyIterator::CalculateNativeAccessorFlags() {
206 2994002 : if (calculated_native_accessor_flags_) return;
207 : Handle<JSReceiver> receiver =
208 2993922 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
209 : native_accessor_flags_ =
210 5987844 : GetNativeAccessorDescriptorInternal(receiver, raw_name());
211 2993922 : calculated_native_accessor_flags_ = true;
212 : }
213 : } // namespace internal
214 122036 : } // namespace v8
|