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.
8 #include "src/factory.h"
9 #include "src/field-index.h"
10 #include "src/field-index-inl.h"
11 #include "src/isolate.h"
12 #include "src/types.h"
19 // Abstraction for elements in instance-descriptor arrays.
21 // Each descriptor has a key, property attributes, property type,
22 // property index (in the actual instance-descriptor array) and
23 // optionally a piece of data.
24 class Descriptor BASE_EMBEDDED {
26 void KeyToUniqueName() {
27 if (!key_->IsUniqueName()) {
28 key_ = key_->GetIsolate()->factory()->InternalizeString(
29 Handle<String>::cast(key_));
33 Handle<Name> GetKey() const { return key_; }
34 Handle<Object> GetValue() const { return value_; }
35 PropertyDetails GetDetails() const { return details_; }
37 void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
41 Handle<Object> value_;
42 PropertyDetails details_;
45 Descriptor() : details_(Smi::FromInt(0)) {}
47 void Init(Handle<Name> key, Handle<Object> value, PropertyDetails details) {
53 Descriptor(Handle<Name> key, Handle<Object> value, PropertyDetails details)
58 Descriptor(Handle<Name> key,
60 PropertyAttributes attributes,
62 Representation representation,
66 details_(attributes, type, representation, field_index) { }
68 friend class DescriptorArray;
73 OStream& operator<<(OStream& os, const Descriptor& d);
76 class FieldDescriptor V8_FINAL : public Descriptor {
78 FieldDescriptor(Handle<Name> key,
80 PropertyAttributes attributes,
81 Representation representation)
82 : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
83 FIELD, representation, field_index) {}
84 FieldDescriptor(Handle<Name> key,
86 Handle<HeapType> field_type,
87 PropertyAttributes attributes,
88 Representation representation)
89 : Descriptor(key, field_type, attributes, FIELD,
90 representation, field_index) { }
94 class ConstantDescriptor V8_FINAL : public Descriptor {
96 ConstantDescriptor(Handle<Name> key,
98 PropertyAttributes attributes)
99 : Descriptor(key, value, attributes, CONSTANT,
100 value->OptimalRepresentation()) {}
104 class CallbacksDescriptor V8_FINAL : public Descriptor {
106 CallbacksDescriptor(Handle<Name> key,
107 Handle<Object> foreign,
108 PropertyAttributes attributes)
109 : Descriptor(key, foreign, attributes, CALLBACKS,
110 Representation::Tagged()) {}
114 class LookupResult V8_FINAL BASE_EMBEDDED {
116 explicit LookupResult(Isolate* isolate)
118 next_(isolate->top_lookup_result()),
119 lookup_type_(NOT_FOUND),
123 details_(NONE, NONEXISTENT, Representation::None()) {
124 isolate->set_top_lookup_result(this);
128 DCHECK(isolate()->top_lookup_result() == this);
129 isolate()->set_top_lookup_result(next_);
132 Isolate* isolate() const { return isolate_; }
134 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
135 lookup_type_ = DESCRIPTOR_TYPE;
142 bool CanHoldValue(Handle<Object> value) const {
147 return value->FitsRepresentation(representation()) &&
148 GetFieldType()->NowContains(value);
150 DCHECK(GetConstant() != *value ||
151 value->FitsRepresentation(representation()));
152 return GetConstant() == *value;
164 void TransitionResult(JSObject* holder, Map* target) {
165 lookup_type_ = TRANSITION_TYPE;
166 number_ = target->LastAdded();
167 details_ = target->instance_descriptors()->GetDetails(number_);
169 transition_ = target;
172 void DictionaryResult(JSObject* holder, int entry) {
173 lookup_type_ = DICTIONARY_TYPE;
176 details_ = holder->property_dictionary()->DetailsAt(entry);
180 void HandlerResult(JSProxy* proxy) {
181 lookup_type_ = HANDLER_TYPE;
184 details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
188 void InterceptorResult(JSObject* holder) {
189 lookup_type_ = INTERCEPTOR_TYPE;
192 details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
196 lookup_type_ = NOT_FOUND;
197 details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
202 JSObject* holder() const {
204 return JSObject::cast(holder_);
207 JSProxy* proxy() const {
209 return JSProxy::cast(holder_);
212 PropertyType type() const {
214 return details_.type();
217 Representation representation() const {
219 DCHECK(details_.type() != NONEXISTENT);
220 return details_.representation();
223 PropertyAttributes GetAttributes() const {
225 DCHECK(details_.type() != NONEXISTENT);
226 return details_.attributes();
229 PropertyDetails GetPropertyDetails() const {
233 bool IsFastPropertyType() const {
235 return IsTransition() || type() != NORMAL;
238 // Property callbacks does not include transitions to callbacks.
239 bool IsPropertyCallbacks() const {
240 DCHECK(!(details_.type() == CALLBACKS && !IsFound()));
241 return !IsTransition() && details_.type() == CALLBACKS;
244 bool IsReadOnly() const {
246 DCHECK(details_.type() != NONEXISTENT);
247 return details_.IsReadOnly();
250 bool IsField() const {
251 DCHECK(!(details_.type() == FIELD && !IsFound()));
252 return IsDescriptorOrDictionary() && type() == FIELD;
255 bool IsNormal() const {
256 DCHECK(!(details_.type() == NORMAL && !IsFound()));
257 return IsDescriptorOrDictionary() && type() == NORMAL;
260 bool IsConstant() const {
261 DCHECK(!(details_.type() == CONSTANT && !IsFound()));
262 return IsDescriptorOrDictionary() && type() == CONSTANT;
265 bool IsConstantFunction() const {
266 return IsConstant() && GetConstant()->IsJSFunction();
269 bool IsDontDelete() const { return details_.IsDontDelete(); }
270 bool IsDontEnum() const { return details_.IsDontEnum(); }
271 bool IsFound() const { return lookup_type_ != NOT_FOUND; }
272 bool IsDescriptorOrDictionary() const {
273 return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE;
275 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
276 bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; }
277 bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; }
279 // Is the result is a property excluding transitions and the null descriptor?
280 bool IsProperty() const {
281 return IsFound() && !IsTransition();
284 bool IsDataProperty() const {
285 switch (lookup_type_) {
287 case TRANSITION_TYPE:
289 case INTERCEPTOR_TYPE:
292 case DESCRIPTOR_TYPE:
293 case DICTIONARY_TYPE:
300 Object* callback = GetCallbackObject();
301 DCHECK(!callback->IsForeign());
302 return callback->IsAccessorInfo();
315 bool IsCacheable() const { return cacheable_; }
316 void DisallowCaching() { cacheable_ = false; }
318 Object* GetLazyValue() const {
319 switch (lookup_type_) {
321 case TRANSITION_TYPE:
323 case INTERCEPTOR_TYPE:
324 return isolate()->heap()->the_hole_value();
326 case DESCRIPTOR_TYPE:
327 case DICTIONARY_TYPE:
330 return holder()->RawFastPropertyAt(GetFieldIndex());
332 Object* value = holder()->property_dictionary()->ValueAt(
333 GetDictionaryEntry());
334 if (holder()->IsGlobalObject()) {
335 value = PropertyCell::cast(value)->value();
340 return GetConstant();
342 return isolate()->heap()->the_hole_value();
354 Map* GetTransitionTarget() const {
355 DCHECK(IsTransition());
359 bool IsTransitionToField() const {
360 return IsTransition() && details_.type() == FIELD;
363 bool IsTransitionToConstant() const {
364 return IsTransition() && details_.type() == CONSTANT;
367 int GetDescriptorIndex() const {
368 DCHECK(lookup_type_ == DESCRIPTOR_TYPE);
372 FieldIndex GetFieldIndex() const {
373 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
374 lookup_type_ == TRANSITION_TYPE);
375 return FieldIndex::ForLookupResult(this);
378 int GetLocalFieldIndexFromMap(Map* map) const {
379 return GetFieldIndexFromMap(map) - map->inobject_properties();
382 int GetDictionaryEntry() const {
383 DCHECK(lookup_type_ == DICTIONARY_TYPE);
387 JSFunction* GetConstantFunction() const {
388 DCHECK(type() == CONSTANT);
389 return JSFunction::cast(GetValue());
392 Object* GetConstantFromMap(Map* map) const {
393 DCHECK(type() == CONSTANT);
394 return GetValueFromMap(map);
397 JSFunction* GetConstantFunctionFromMap(Map* map) const {
398 return JSFunction::cast(GetConstantFromMap(map));
401 Object* GetConstant() const {
402 DCHECK(type() == CONSTANT);
406 Object* GetCallbackObject() const {
407 DCHECK(!IsTransition());
408 DCHECK(type() == CALLBACKS);
412 Object* GetValue() const {
413 if (lookup_type_ == DESCRIPTOR_TYPE) {
414 return GetValueFromMap(holder()->map());
415 } else if (lookup_type_ == TRANSITION_TYPE) {
416 return GetValueFromMap(transition_);
418 // In the dictionary case, the data is held in the value field.
419 DCHECK(lookup_type_ == DICTIONARY_TYPE);
420 return holder()->GetNormalizedProperty(this);
423 Object* GetValueFromMap(Map* map) const {
424 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
425 lookup_type_ == TRANSITION_TYPE);
426 DCHECK(number_ < map->NumberOfOwnDescriptors());
427 return map->instance_descriptors()->GetValue(number_);
430 int GetFieldIndexFromMap(Map* map) const {
431 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
432 lookup_type_ == TRANSITION_TYPE);
433 DCHECK(number_ < map->NumberOfOwnDescriptors());
434 return map->instance_descriptors()->GetFieldIndex(number_);
437 HeapType* GetFieldType() const {
438 DCHECK(type() == FIELD);
439 if (lookup_type_ == DESCRIPTOR_TYPE) {
440 return GetFieldTypeFromMap(holder()->map());
442 DCHECK(lookup_type_ == TRANSITION_TYPE);
443 return GetFieldTypeFromMap(transition_);
446 HeapType* GetFieldTypeFromMap(Map* map) const {
447 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
448 lookup_type_ == TRANSITION_TYPE);
449 DCHECK(number_ < map->NumberOfOwnDescriptors());
450 return map->instance_descriptors()->GetFieldType(number_);
453 Map* GetFieldOwner() const {
454 return GetFieldOwnerFromMap(holder()->map());
457 Map* GetFieldOwnerFromMap(Map* map) const {
458 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
459 lookup_type_ == TRANSITION_TYPE);
460 DCHECK(number_ < map->NumberOfOwnDescriptors());
461 return map->FindFieldOwner(number_);
464 bool ReceiverIsHolder(Handle<Object> receiver) {
465 if (*receiver == holder()) return true;
466 if (lookup_type_ == TRANSITION_TYPE) return true;
470 void Iterate(ObjectVisitor* visitor);
476 // Where did we find the result;
490 PropertyDetails details_;
494 OStream& operator<<(OStream& os, const LookupResult& r);
495 } } // namespace v8::internal
497 #endif // V8_PROPERTY_H_