V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
debug-property-iterator.cc
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 std::unique_ptr<debug::PropertyIterator> debug::PropertyIterator::Create(
17  v8::Local<v8::Object> v8_object) {
18  internal::Isolate* isolate =
19  reinterpret_cast<internal::Isolate*>(v8_object->GetIsolate());
20  return std::unique_ptr<debug::PropertyIterator>(
21  new internal::DebugPropertyIterator(isolate,
22  Utils::OpenHandle(*v8_object)));
23 }
24 
25 namespace internal {
26 
27 DebugPropertyIterator::DebugPropertyIterator(Isolate* isolate,
28  Handle<JSReceiver> receiver)
29  : isolate_(isolate),
30  prototype_iterator_(isolate, receiver, kStartAtReceiver,
31  PrototypeIterator::END_AT_NULL) {
32  if (receiver->IsJSProxy()) {
33  is_own_ = false;
34  prototype_iterator_.AdvanceIgnoringProxies();
35  }
36  if (prototype_iterator_.IsAtEnd()) return;
37  FillKeysForCurrentPrototypeAndStage();
38  if (should_move_to_next_stage()) Advance();
39 }
40 
41 bool DebugPropertyIterator::Done() const {
42  return prototype_iterator_.IsAtEnd();
43 }
44 
45 void DebugPropertyIterator::Advance() {
46  ++current_key_index_;
47  calculated_native_accessor_flags_ = false;
48  while (should_move_to_next_stage()) {
49  switch (stage_) {
50  case Stage::kExoticIndices:
51  stage_ = Stage::kEnumerableStrings;
52  break;
53  case Stage::kEnumerableStrings:
54  stage_ = Stage::kAllProperties;
55  break;
56  case Stage::kAllProperties:
57  stage_ = kExoticIndices;
58  is_own_ = false;
59  prototype_iterator_.AdvanceIgnoringProxies();
60  break;
61  }
62  FillKeysForCurrentPrototypeAndStage();
63  }
64 }
65 
66 bool DebugPropertyIterator::is_native_accessor() {
67  if (stage_ == kExoticIndices) return false;
68  CalculateNativeAccessorFlags();
69  return native_accessor_flags_;
70 }
71 
72 bool DebugPropertyIterator::has_native_getter() {
73  if (stage_ == kExoticIndices) return false;
74  CalculateNativeAccessorFlags();
75  return native_accessor_flags_ &
76  static_cast<int>(debug::NativeAccessorType::HasGetter);
77 }
78 
79 bool DebugPropertyIterator::has_native_setter() {
80  if (stage_ == kExoticIndices) return false;
81  CalculateNativeAccessorFlags();
82  return native_accessor_flags_ &
83  static_cast<int>(debug::NativeAccessorType::HasSetter);
84 }
85 
86 Handle<Name> DebugPropertyIterator::raw_name() const {
87  DCHECK(!Done());
88  if (stage_ == kExoticIndices) {
89  return isolate_->factory()->Uint32ToString(current_key_index_);
90  } else {
91  return Handle<Name>::cast(
92  FixedArray::get(*keys_, current_key_index_, isolate_));
93  }
94 }
95 
96 v8::Local<v8::Name> DebugPropertyIterator::name() const {
97  return Utils::ToLocal(raw_name());
98 }
99 
100 v8::Maybe<v8::PropertyAttribute> DebugPropertyIterator::attributes() {
101  Handle<JSReceiver> receiver =
102  PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
103  auto result = JSReceiver::GetPropertyAttributes(receiver, raw_name());
104  if (result.IsNothing()) return Nothing<v8::PropertyAttribute>();
105  DCHECK(result.FromJust() != ABSENT);
106  return Just(static_cast<v8::PropertyAttribute>(result.FromJust()));
107 }
108 
109 v8::Maybe<v8::debug::PropertyDescriptor> DebugPropertyIterator::descriptor() {
110  Handle<JSReceiver> receiver =
111  PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
112 
113  PropertyDescriptor descriptor;
114  Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
115  isolate_, receiver, raw_name(), &descriptor);
116  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())
126  descriptor.has_get() ? Utils::ToLocal(descriptor.get())
128  descriptor.has_set() ? Utils::ToLocal(descriptor.set())
130  });
131 }
132 
133 bool DebugPropertyIterator::is_own() { return is_own_; }
134 
135 bool DebugPropertyIterator::is_array_index() {
136  if (stage_ == kExoticIndices) return true;
137  uint32_t index = 0;
138  return raw_name()->AsArrayIndex(&index);
139 }
140 
141 void DebugPropertyIterator::FillKeysForCurrentPrototypeAndStage() {
142  current_key_index_ = 0;
143  exotic_length_ = 0;
144  keys_ = Handle<FixedArray>::null();
145  if (prototype_iterator_.IsAtEnd()) return;
146  Handle<JSReceiver> receiver =
147  PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
148  bool has_exotic_indices = receiver->IsJSTypedArray();
149  if (stage_ == kExoticIndices) {
150  if (!has_exotic_indices) return;
151  exotic_length_ = static_cast<uint32_t>(
152  Handle<JSTypedArray>::cast(receiver)->length_value());
153  return;
154  }
155  bool skip_indices = has_exotic_indices;
156  PropertyFilter filter =
157  stage_ == kEnumerableStrings ? ENUMERABLE_STRINGS : ALL_PROPERTIES;
158  if (!KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
159  GetKeysConversion::kConvertToString, false,
160  skip_indices)
161  .ToHandle(&keys_)) {
162  keys_ = Handle<FixedArray>::null();
163  }
164 }
165 
166 bool DebugPropertyIterator::should_move_to_next_stage() const {
167  if (prototype_iterator_.IsAtEnd()) return false;
168  if (stage_ == kExoticIndices) return current_key_index_ >= exotic_length_;
169  return keys_.is_null() ||
170  current_key_index_ >= static_cast<uint32_t>(keys_->length());
171 }
172 
173 namespace {
174 base::Flags<debug::NativeAccessorType, int> GetNativeAccessorDescriptorInternal(
175  Handle<JSReceiver> object, Handle<Name> name) {
176  uint32_t index;
177  if (name->AsArrayIndex(&index)) return debug::NativeAccessorType::None;
178  LookupIterator it =
179  LookupIterator(object->GetIsolate(), object, name, LookupIterator::OWN);
180  if (!it.IsFound()) return debug::NativeAccessorType::None;
181  if (it.state() != LookupIterator::ACCESSOR) {
182  return debug::NativeAccessorType::None;
183  }
184  Handle<Object> structure = it.GetAccessors();
185  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  ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */)
192 #undef IS_BUILTIN_ACESSOR
193  Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
194  if (accessor_info->getter()) {
195  result |= debug::NativeAccessorType::HasGetter;
196  }
197  if (accessor_info->setter()) {
198  result |= debug::NativeAccessorType::HasSetter;
199  }
200  return result;
201 }
202 } // anonymous namespace
203 
204 void DebugPropertyIterator::CalculateNativeAccessorFlags() {
205  if (calculated_native_accessor_flags_) return;
206  Handle<JSReceiver> receiver =
207  PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
208  native_accessor_flags_ =
209  GetNativeAccessorDescriptorInternal(receiver, raw_name());
210  calculated_native_accessor_flags_ = true;
211 }
212 } // namespace internal
213 } // namespace v8
Isolate * GetIsolate()
Definition: api.cc:6700
Definition: v8.h:56
Definition: libplatform.h:13
PropertyFilter
Definition: v8.h:3185