V8 Project
lookup.cc
Go to the documentation of this file.
1 // Copyright 2014 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/v8.h"
6 
7 #include "src/bootstrapper.h"
8 #include "src/deoptimizer.h"
9 #include "src/lookup.h"
10 #include "src/lookup-inl.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 
16 void LookupIterator::Next() {
17  DCHECK_NE(JSPROXY, state_);
18  DCHECK_NE(TRANSITION, state_);
20  has_property_ = false;
21 
22  JSReceiver* holder = *holder_;
23  Map* map = *holder_map_;
24 
25  // Perform lookup on current holder.
26  state_ = LookupInHolder(map, holder);
27  if (IsFound()) return;
28 
29  // Continue lookup if lookup on current holder failed.
30  do {
31  JSReceiver* maybe_holder = NextHolder(map);
32  if (maybe_holder == NULL) break;
33  holder = maybe_holder;
34  map = holder->map();
35  state_ = LookupInHolder(map, holder);
36  } while (!IsFound());
37 
38  if (holder != *holder_) {
39  holder_ = handle(holder, isolate_);
40  holder_map_ = handle(map, isolate_);
41  }
42 }
43 
44 
45 Handle<JSReceiver> LookupIterator::GetRoot() const {
46  if (receiver_->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver_);
47  Handle<Object> root =
48  handle(receiver_->GetRootMap(isolate_)->prototype(), isolate_);
49  CHECK(!root->IsNull());
50  return Handle<JSReceiver>::cast(root);
51 }
52 
53 
54 Handle<Map> LookupIterator::GetReceiverMap() const {
55  if (receiver_->IsNumber()) return isolate_->factory()->heap_number_map();
56  return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
57 }
58 
59 
60 Handle<JSObject> LookupIterator::GetStoreTarget() const {
61  if (receiver_->IsJSGlobalProxy()) {
62  PrototypeIterator iter(isolate(), receiver_);
63  if (iter.IsAtEnd()) return Handle<JSGlobalProxy>::cast(receiver_);
65  }
66  return Handle<JSObject>::cast(receiver_);
67 }
68 
69 
70 bool LookupIterator::IsBootstrapping() const {
71  return isolate_->bootstrapper()->IsActive();
72 }
73 
74 
75 bool LookupIterator::HasAccess(v8::AccessType access_type) const {
76  DCHECK_EQ(ACCESS_CHECK, state_);
77  return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type);
78 }
79 
80 
81 void LookupIterator::ReloadPropertyInformation() {
82  state_ = BEFORE_PROPERTY;
83  state_ = LookupInHolder(*holder_map_, *holder_);
84  DCHECK(IsFound() || holder_map_->is_dictionary_map());
85 }
86 
87 
88 void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
89  DCHECK(state_ == DATA || state_ == ACCESSOR);
90  DCHECK(HolderIsReceiverOrHiddenPrototype());
91  if (holder_map_->is_dictionary_map()) return;
92  holder_map_ =
93  Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
94  JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_);
95  ReloadPropertyInformation();
96 }
97 
98 
99 void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
100  PropertyAttributes attributes) {
101  DCHECK(state_ == DATA || state_ == ACCESSOR);
102  DCHECK(HolderIsReceiverOrHiddenPrototype());
103  Handle<JSObject> holder = GetHolder<JSObject>();
104  if (holder_map_->is_dictionary_map()) {
105  PropertyDetails details(attributes, NORMAL, 0);
106  JSObject::SetNormalizedProperty(holder, name(), value, details);
107  } else {
108  holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(),
109  attributes);
110  JSObject::MigrateToMap(holder, holder_map_);
111  }
112 
113  ReloadPropertyInformation();
114 }
115 
116 
117 void LookupIterator::PrepareTransitionToDataProperty(
118  Handle<Object> value, PropertyAttributes attributes,
119  Object::StoreFromKeyed store_mode) {
120  if (state_ == TRANSITION) return;
121  DCHECK(state_ != LookupIterator::ACCESSOR ||
122  GetAccessors()->IsDeclaredAccessorInfo());
123  DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
124 
125  // Can only be called when the receiver is a JSObject. JSProxy has to be
126  // handled via a trap. Adding properties to primitive values is not
127  // observable.
128  Handle<JSObject> receiver = GetStoreTarget();
129 
130  if (!name().is_identical_to(isolate()->factory()->hidden_string()) &&
131  !receiver->map()->is_extensible()) {
132  return;
133  }
134 
135  transition_map_ = Map::TransitionToDataProperty(
136  handle(receiver->map(), isolate_), name_, value, attributes, store_mode);
137  state_ = TRANSITION;
138 }
139 
140 
141 void LookupIterator::ApplyTransitionToDataProperty() {
142  DCHECK_EQ(TRANSITION, state_);
143 
144  Handle<JSObject> receiver = GetStoreTarget();
145  holder_ = receiver;
146  holder_map_ = transition_map_;
147  JSObject::MigrateToMap(receiver, holder_map_);
148  ReloadPropertyInformation();
149 }
150 
151 
152 void LookupIterator::TransitionToAccessorProperty(
153  AccessorComponent component, Handle<Object> accessor,
154  PropertyAttributes attributes) {
155  DCHECK(!accessor->IsNull());
156  // Can only be called when the receiver is a JSObject. JSProxy has to be
157  // handled via a trap. Adding properties to primitive values is not
158  // observable.
159  Handle<JSObject> receiver = GetStoreTarget();
160  holder_ = receiver;
161  holder_map_ =
162  Map::TransitionToAccessorProperty(handle(receiver->map(), isolate_),
163  name_, component, accessor, attributes);
164  JSObject::MigrateToMap(receiver, holder_map_);
165 
166  ReloadPropertyInformation();
167 
168  if (!holder_map_->is_dictionary_map()) return;
169 
170  // We have to deoptimize since accesses to data properties may have been
171  // inlined without a corresponding map-check.
172  if (holder_map_->IsGlobalObjectMap()) {
174  }
175 
176  // Install the accessor into the dictionary-mode object.
177  PropertyDetails details(attributes, CALLBACKS, 0);
178  Handle<AccessorPair> pair;
179  if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
180  pair = Handle<AccessorPair>::cast(GetAccessors());
181  // If the component and attributes are identical, nothing has to be done.
182  if (pair->get(component) == *accessor) {
183  if (property_details().attributes() == attributes) return;
184  } else {
185  pair = AccessorPair::Copy(pair);
186  pair->set(component, *accessor);
187  }
188  } else {
189  pair = isolate()->factory()->NewAccessorPair();
190  pair->set(component, *accessor);
191  }
192  JSObject::SetNormalizedProperty(receiver, name_, pair, details);
193 
195  holder_map_ = handle(receiver->map(), isolate_);
196  ReloadPropertyInformation();
197 }
198 
199 
200 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
201  DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
202  // Optimization that only works if configuration_ is not mutable.
203  if (!check_prototype_chain()) return true;
205  if (!receiver_->IsJSReceiver()) return false;
206  Object* current = *receiver_;
207  JSReceiver* holder = *holder_;
208  // JSProxy do not occur as hidden prototypes.
209  if (current->IsJSProxy()) {
210  return JSReceiver::cast(current) == holder;
211  }
212  PrototypeIterator iter(isolate(), current,
214  do {
215  if (JSReceiver::cast(iter.GetCurrent()) == holder) return true;
216  DCHECK(!current->IsJSProxy());
217  iter.Advance();
218  } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
219  return false;
220 }
221 
222 
223 Handle<Object> LookupIterator::FetchValue() const {
224  Object* result = NULL;
225  Handle<JSObject> holder = GetHolder<JSObject>();
226  if (holder_map_->is_dictionary_map()) {
227  result = holder->property_dictionary()->ValueAt(number_);
228  if (holder_map_->IsGlobalObjectMap()) {
229  result = PropertyCell::cast(result)->value();
230  }
231  } else if (property_details_.type() == v8::internal::FIELD) {
232  FieldIndex field_index = FieldIndex::ForDescriptor(*holder_map_, number_);
233  return JSObject::FastPropertyAt(holder, property_details_.representation(),
234  field_index);
235  } else {
236  result = holder_map_->instance_descriptors()->GetValue(number_);
237  }
238  return handle(result, isolate_);
239 }
240 
241 
242 int LookupIterator::GetConstantIndex() const {
243  DCHECK(has_property_);
244  DCHECK(!holder_map_->is_dictionary_map());
245  DCHECK_EQ(v8::internal::CONSTANT, property_details_.type());
246  return descriptor_number();
247 }
248 
249 
250 FieldIndex LookupIterator::GetFieldIndex() const {
251  DCHECK(has_property_);
252  DCHECK(!holder_map_->is_dictionary_map());
253  DCHECK_EQ(v8::internal::FIELD, property_details_.type());
254  int index =
255  holder_map_->instance_descriptors()->GetFieldIndex(descriptor_number());
256  bool is_double = representation().IsDouble();
257  return FieldIndex::ForPropertyIndex(*holder_map_, index, is_double);
258 }
259 
260 
261 Handle<HeapType> LookupIterator::GetFieldType() const {
262  DCHECK(has_property_);
263  DCHECK(!holder_map_->is_dictionary_map());
264  DCHECK_EQ(v8::internal::FIELD, property_details_.type());
265  return handle(
266  holder_map_->instance_descriptors()->GetFieldType(descriptor_number()),
267  isolate_);
268 }
269 
270 
271 Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
272  Handle<JSObject> holder = GetHolder<JSObject>();
273  Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
274  Object* value = global->property_dictionary()->ValueAt(dictionary_entry());
275  return Handle<PropertyCell>(PropertyCell::cast(value));
276 }
277 
278 
279 Handle<Object> LookupIterator::GetAccessors() const {
280  DCHECK_EQ(ACCESSOR, state_);
281  return FetchValue();
282 }
283 
284 
285 Handle<Object> LookupIterator::GetDataValue() const {
286  DCHECK_EQ(DATA, state_);
287  Handle<Object> value = FetchValue();
288  return value;
289 }
290 
291 
292 void LookupIterator::WriteDataValue(Handle<Object> value) {
293  DCHECK_EQ(DATA, state_);
294  Handle<JSObject> holder = GetHolder<JSObject>();
295  if (holder_map_->is_dictionary_map()) {
296  NameDictionary* property_dictionary = holder->property_dictionary();
297  if (holder->IsGlobalObject()) {
298  Handle<PropertyCell> cell(
299  PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry())));
300  PropertyCell::SetValueInferType(cell, value);
301  } else {
302  property_dictionary->ValueAtPut(dictionary_entry(), *value);
303  }
304  } else if (property_details_.type() == v8::internal::FIELD) {
305  holder->WriteToField(descriptor_number(), *value);
306  } else {
307  DCHECK_EQ(v8::internal::CONSTANT, property_details_.type());
308  }
309 }
310 
311 
312 void LookupIterator::InternalizeName() {
313  if (name_->IsUniqueName()) return;
314  name_ = factory()->InternalizeString(Handle<String>::cast(name_));
315 }
316 } } // namespace v8::internal
static Handle< AccessorPair > Copy(Handle< AccessorPair > pair)
Definition: objects.cc:7904
static void DeoptimizeGlobalObject(JSObject *object)
Definition: deoptimizer.cc:470
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
static void ReoptimizeIfPrototype(Handle< JSObject > object)
Definition: objects.cc:9349
static Handle< Object > FastPropertyAt(Handle< JSObject > object, Representation representation, FieldIndex index)
Definition: objects.cc:5362
static void MigrateToMap(Handle< JSObject > object, Handle< Map > new_map)
Definition: objects.cc:1886
static void SetNormalizedProperty(Handle< JSObject > object, Handle< Name > key, Handle< Object > value, PropertyDetails details)
Definition: objects.cc:641
static Handle< Map > TransitionToAccessorProperty(Handle< Map > map, Handle< Name > name, AccessorComponent component, Handle< Object > accessor, PropertyAttributes attributes)
Definition: objects.cc:6816
static Handle< Map > PrepareForDataProperty(Handle< Map > old_map, int descriptor_number, Handle< Object > value)
Definition: objects.cc:6738
static Handle< Map > ReconfigureDataProperty(Handle< Map > map, int descriptor, PropertyAttributes attributes)
Definition: objects.cc:6804
static Handle< Map > TransitionToDataProperty(Handle< Map > map, Handle< Name > name, Handle< Object > value, PropertyAttributes attributes, StoreFromKeyed store_mode)
Definition: objects.cc:6759
static void SetValueInferType(Handle< PropertyCell > cell, Handle< Object > value)
Definition: objects.cc:16367
Object * GetCurrent() const
Definition: prototype.h:62
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define CHECK(condition)
Definition: logging.h:36
#define DCHECK_NE(v1, v2)
Definition: logging.h:207
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
PerThreadAssertScopeDebugOnly< HEAP_ALLOCATION_ASSERT, false > DisallowHeapAllocation
Definition: assert-scope.h:110
kSerializedDataOffset Object
Definition: objects-inl.h:5322
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
AccessType
Access type specification.
Definition: v8.h:3519
PropertyAttributes