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 79157 : std::unique_ptr<debug::PropertyIterator> debug::PropertyIterator::Create(
17 : v8::Local<v8::Object> v8_object) {
18 : internal::Isolate* isolate =
19 79157 : reinterpret_cast<internal::Isolate*>(v8_object->GetIsolate());
20 : return std::unique_ptr<debug::PropertyIterator>(
21 : new internal::DebugPropertyIterator(isolate,
22 158314 : Utils::OpenHandle(*v8_object)));
23 : }
24 :
25 : namespace internal {
26 :
27 79157 : DebugPropertyIterator::DebugPropertyIterator(Isolate* isolate,
28 : Handle<JSReceiver> receiver)
29 : : isolate_(isolate),
30 : prototype_iterator_(isolate, receiver, kStartAtReceiver,
31 237471 : PrototypeIterator::END_AT_NULL) {
32 158314 : if (receiver->IsJSProxy()) {
33 15 : is_own_ = false;
34 15 : prototype_iterator_.AdvanceIgnoringProxies();
35 : }
36 158314 : if (prototype_iterator_.IsAtEnd()) return;
37 79142 : FillKeysForCurrentPrototypeAndStage();
38 79142 : if (should_move_to_next_stage()) Advance();
39 : }
40 :
41 4515483 : bool DebugPropertyIterator::Done() const {
42 4515483 : return prototype_iterator_.IsAtEnd();
43 : }
44 :
45 4515383 : void DebugPropertyIterator::Advance() {
46 4515383 : ++current_key_index_;
47 4515383 : calculated_native_accessor_flags_ = false;
48 9361756 : while (should_move_to_next_stage()) {
49 330990 : switch (stage_) {
50 : case Stage::kExoticIndices:
51 123821 : stage_ = Stage::kEnumerableStrings;
52 123821 : break;
53 : case Stage::kEnumerableStrings:
54 105913 : stage_ = Stage::kAllProperties;
55 105913 : break;
56 : case Stage::kAllProperties:
57 101256 : stage_ = kExoticIndices;
58 101256 : is_own_ = false;
59 101256 : prototype_iterator_.AdvanceIgnoringProxies();
60 101256 : break;
61 : }
62 330990 : FillKeysForCurrentPrototypeAndStage();
63 : }
64 4515383 : }
65 :
66 2978403 : bool DebugPropertyIterator::is_native_accessor() {
67 2978403 : if (stage_ == kExoticIndices) return false;
68 2977132 : CalculateNativeAccessorFlags();
69 2977132 : 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 16347411 : Handle<Name> DebugPropertyIterator::raw_name() const {
87 : DCHECK(!Done());
88 16347411 : if (stage_ == kExoticIndices) {
89 3813 : return isolate_->factory()->Uint32ToString(current_key_index_);
90 : } else {
91 : return Handle<Name>::cast(
92 32687196 : FixedArray::get(*keys_, current_key_index_, isolate_));
93 : }
94 : }
95 :
96 4436371 : v8::Local<v8::Name> DebugPropertyIterator::name() const {
97 4436371 : return Utils::ToLocal(raw_name());
98 : }
99 :
100 2978403 : v8::Maybe<v8::PropertyAttribute> DebugPropertyIterator::attributes() {
101 : Handle<JSReceiver> receiver =
102 2978403 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
103 2978403 : auto result = JSReceiver::GetPropertyAttributes(receiver, raw_name());
104 2978403 : if (result.IsNothing()) return Nothing<v8::PropertyAttribute>();
105 : DCHECK(result.FromJust() != ABSENT);
106 : return Just(static_cast<v8::PropertyAttribute>(result.FromJust()));
107 : }
108 :
109 2978383 : v8::Maybe<v8::debug::PropertyDescriptor> DebugPropertyIterator::descriptor() {
110 : Handle<JSReceiver> receiver =
111 2978383 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
112 :
113 : PropertyDescriptor descriptor;
114 : Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
115 5956766 : isolate_, receiver, raw_name(), &descriptor);
116 2978383 : 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 8935149 : });
131 : }
132 :
133 4458901 : bool DebugPropertyIterator::is_own() { return is_own_; }
134 :
135 2978393 : bool DebugPropertyIterator::is_array_index() {
136 2978393 : if (stage_ == kExoticIndices) return true;
137 2977122 : uint32_t index = 0;
138 5954244 : return raw_name()->AsArrayIndex(&index);
139 : }
140 :
141 410132 : void DebugPropertyIterator::FillKeysForCurrentPrototypeAndStage() {
142 410132 : current_key_index_ = 0;
143 410132 : exotic_length_ = 0;
144 410132 : keys_ = Handle<FixedArray>::null();
145 410132 : if (prototype_iterator_.IsAtEnd()) return;
146 : Handle<JSReceiver> receiver =
147 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
148 707130 : bool has_exotic_indices = receiver->IsJSTypedArray();
149 353565 : if (stage_ == kExoticIndices) {
150 123831 : 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 229734 : stage_ == kEnumerableStrings ? ENUMERABLE_STRINGS : ALL_PROPERTIES;
158 229734 : if (!KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
159 : GetKeysConversion::kConvertToString, false,
160 229734 : skip_indices)
161 689202 : .ToHandle(&keys_)) {
162 0 : keys_ = Handle<FixedArray>::null();
163 : }
164 : }
165 :
166 4925515 : bool DebugPropertyIterator::should_move_to_next_stage() const {
167 4925515 : if (prototype_iterator_.IsAtEnd()) return false;
168 4868948 : if (stage_ == kExoticIndices) return current_key_index_ >= exotic_length_;
169 9329598 : return keys_.is_null() ||
170 13994397 : current_key_index_ >= static_cast<uint32_t>(keys_->length());
171 : }
172 :
173 : namespace {
174 2977132 : base::Flags<debug::NativeAccessorType, int> GetNativeAccessorDescriptorInternal(
175 : Handle<JSReceiver> object, Handle<Name> name) {
176 : uint32_t index;
177 2977132 : if (name->AsArrayIndex(&index)) return debug::NativeAccessorType::None;
178 : LookupIterator it =
179 2945635 : LookupIterator(object->GetIsolate(), object, name, LookupIterator::OWN);
180 2945635 : if (!it.IsFound()) return debug::NativeAccessorType::None;
181 2945635 : if (it.state() != LookupIterator::ACCESSOR) {
182 2903743 : return debug::NativeAccessorType::None;
183 : }
184 41892 : Handle<Object> structure = it.GetAccessors();
185 83784 : 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 23909 : 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 40 : if (accessor_info->getter() != Object()) {
195 : result |= debug::NativeAccessorType::HasGetter;
196 : }
197 40 : if (accessor_info->setter() != Object()) {
198 : result |= debug::NativeAccessorType::HasSetter;
199 : }
200 20 : return result;
201 : }
202 : } // anonymous namespace
203 :
204 2977172 : void DebugPropertyIterator::CalculateNativeAccessorFlags() {
205 2977212 : if (calculated_native_accessor_flags_) return;
206 : Handle<JSReceiver> receiver =
207 2977132 : PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
208 5954264 : native_accessor_flags_ =
209 5954264 : GetNativeAccessorDescriptorInternal(receiver, raw_name());
210 2977132 : calculated_native_accessor_flags_ = true;
211 : }
212 : } // namespace internal
213 183867 : } // namespace v8
|