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/isolate.h"
9 #include "src/factory.h"
10 #include "src/field-index.h"
11 #include "src/field-index-inl.h"
12 #include "src/types.h"
17 // Abstraction for elements in instance-descriptor arrays.
19 // Each descriptor has a key, property attributes, property type,
20 // property index (in the actual instance-descriptor array) and
21 // optionally a piece of data.
22 class Descriptor BASE_EMBEDDED {
24 void KeyToUniqueName() {
25 if (!key_->IsUniqueName()) {
26 key_ = key_->GetIsolate()->factory()->InternalizeString(
27 Handle<String>::cast(key_));
31 Handle<Name> GetKey() { return key_; }
32 Handle<Object> GetValue() { return value_; }
33 PropertyDetails GetDetails() { return details_; }
36 void Print(FILE* out);
39 void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
43 Handle<Object> value_;
44 PropertyDetails details_;
47 Descriptor() : details_(Smi::FromInt(0)) {}
49 void Init(Handle<Name> key, Handle<Object> value, PropertyDetails details) {
55 Descriptor(Handle<Name> key, Handle<Object> value, PropertyDetails details)
60 Descriptor(Handle<Name> key,
62 PropertyAttributes attributes,
64 Representation representation,
68 details_(attributes, type, representation, field_index) { }
70 friend class DescriptorArray;
75 class FieldDescriptor V8_FINAL : public Descriptor {
77 FieldDescriptor(Handle<Name> key,
79 PropertyAttributes attributes,
80 Representation representation)
81 : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
82 FIELD, representation, field_index) {}
83 FieldDescriptor(Handle<Name> key,
85 Handle<HeapType> field_type,
86 PropertyAttributes attributes,
87 Representation representation)
88 : Descriptor(key, field_type, attributes, FIELD,
89 representation, field_index) { }
93 class ConstantDescriptor V8_FINAL : public Descriptor {
95 ConstantDescriptor(Handle<Name> key,
97 PropertyAttributes attributes)
98 : Descriptor(key, value, attributes, CONSTANT,
99 value->OptimalRepresentation()) {}
103 class CallbacksDescriptor V8_FINAL : public Descriptor {
105 CallbacksDescriptor(Handle<Name> key,
106 Handle<Object> foreign,
107 PropertyAttributes attributes)
108 : Descriptor(key, foreign, attributes, CALLBACKS,
109 Representation::Tagged()) {}
113 class LookupResult V8_FINAL BASE_EMBEDDED {
115 explicit LookupResult(Isolate* isolate)
117 next_(isolate->top_lookup_result()),
118 lookup_type_(NOT_FOUND),
122 details_(NONE, NONEXISTENT, Representation::None()) {
123 isolate->set_top_lookup_result(this);
127 ASSERT(isolate()->top_lookup_result() == this);
128 isolate()->set_top_lookup_result(next_);
131 Isolate* isolate() const { return isolate_; }
133 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
134 lookup_type_ = DESCRIPTOR_TYPE;
141 bool CanHoldValue(Handle<Object> value) const {
146 return value->FitsRepresentation(representation()) &&
147 GetFieldType()->NowContains(value);
149 ASSERT(GetConstant() != *value ||
150 value->FitsRepresentation(representation()));
151 return GetConstant() == *value;
163 void TransitionResult(JSObject* holder, Map* target) {
164 lookup_type_ = TRANSITION_TYPE;
165 number_ = target->LastAdded();
166 details_ = target->instance_descriptors()->GetDetails(number_);
168 transition_ = target;
171 void DictionaryResult(JSObject* holder, int entry) {
172 lookup_type_ = DICTIONARY_TYPE;
175 details_ = holder->property_dictionary()->DetailsAt(entry);
179 void HandlerResult(JSProxy* proxy) {
180 lookup_type_ = HANDLER_TYPE;
183 details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
187 void InterceptorResult(JSObject* holder) {
188 lookup_type_ = INTERCEPTOR_TYPE;
191 details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
195 lookup_type_ = NOT_FOUND;
196 details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
201 JSObject* holder() const {
203 return JSObject::cast(holder_);
206 JSProxy* proxy() const {
208 return JSProxy::cast(holder_);
211 PropertyType type() const {
213 return details_.type();
216 Representation representation() const {
218 ASSERT(details_.type() != NONEXISTENT);
219 return details_.representation();
222 PropertyAttributes GetAttributes() const {
224 ASSERT(details_.type() != NONEXISTENT);
225 return details_.attributes();
228 PropertyDetails GetPropertyDetails() const {
232 bool IsFastPropertyType() const {
234 return IsTransition() || type() != NORMAL;
237 // Property callbacks does not include transitions to callbacks.
238 bool IsPropertyCallbacks() const {
239 ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
240 return !IsTransition() && details_.type() == CALLBACKS;
243 bool IsReadOnly() const {
245 ASSERT(details_.type() != NONEXISTENT);
246 return details_.IsReadOnly();
249 bool IsField() const {
250 ASSERT(!(details_.type() == FIELD && !IsFound()));
251 return IsDescriptorOrDictionary() && type() == FIELD;
254 bool IsNormal() const {
255 ASSERT(!(details_.type() == NORMAL && !IsFound()));
256 return IsDescriptorOrDictionary() && type() == NORMAL;
259 bool IsConstant() const {
260 ASSERT(!(details_.type() == CONSTANT && !IsFound()));
261 return IsDescriptorOrDictionary() && type() == CONSTANT;
264 bool IsConstantFunction() const {
265 return IsConstant() && GetConstant()->IsJSFunction();
268 bool IsDontDelete() const { return details_.IsDontDelete(); }
269 bool IsDontEnum() const { return details_.IsDontEnum(); }
270 bool IsFound() const { return lookup_type_ != NOT_FOUND; }
271 bool IsDescriptorOrDictionary() const {
272 return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE;
274 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
275 bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; }
276 bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; }
278 // Is the result is a property excluding transitions and the null descriptor?
279 bool IsProperty() const {
280 return IsFound() && !IsTransition();
283 bool IsDataProperty() const {
284 switch (lookup_type_) {
286 case TRANSITION_TYPE:
288 case INTERCEPTOR_TYPE:
291 case DESCRIPTOR_TYPE:
292 case DICTIONARY_TYPE:
299 Object* callback = GetCallbackObject();
300 ASSERT(!callback->IsForeign());
301 return callback->IsAccessorInfo();
314 bool IsCacheable() const { return cacheable_; }
315 void DisallowCaching() { cacheable_ = false; }
317 Object* GetLazyValue() const {
318 switch (lookup_type_) {
320 case TRANSITION_TYPE:
322 case INTERCEPTOR_TYPE:
323 return isolate()->heap()->the_hole_value();
325 case DESCRIPTOR_TYPE:
326 case DICTIONARY_TYPE:
329 return holder()->RawFastPropertyAt(GetFieldIndex());
331 Object* value = holder()->property_dictionary()->ValueAt(
332 GetDictionaryEntry());
333 if (holder()->IsGlobalObject()) {
334 value = PropertyCell::cast(value)->value();
339 return GetConstant();
341 return isolate()->heap()->the_hole_value();
353 Map* GetTransitionTarget() const {
354 ASSERT(IsTransition());
358 bool IsTransitionToField() const {
359 return IsTransition() && details_.type() == FIELD;
362 bool IsTransitionToConstant() const {
363 return IsTransition() && details_.type() == CONSTANT;
366 int GetDescriptorIndex() const {
367 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
371 FieldIndex GetFieldIndex() const {
372 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
373 lookup_type_ == TRANSITION_TYPE);
374 return FieldIndex::ForLookupResult(this);
377 int GetLocalFieldIndexFromMap(Map* map) const {
378 return GetFieldIndexFromMap(map) - map->inobject_properties();
381 int GetDictionaryEntry() const {
382 ASSERT(lookup_type_ == DICTIONARY_TYPE);
386 JSFunction* GetConstantFunction() const {
387 ASSERT(type() == CONSTANT);
388 return JSFunction::cast(GetValue());
391 Object* GetConstantFromMap(Map* map) const {
392 ASSERT(type() == CONSTANT);
393 return GetValueFromMap(map);
396 JSFunction* GetConstantFunctionFromMap(Map* map) const {
397 return JSFunction::cast(GetConstantFromMap(map));
400 Object* GetConstant() const {
401 ASSERT(type() == CONSTANT);
405 Object* GetCallbackObject() const {
406 ASSERT(!IsTransition());
407 ASSERT(type() == CALLBACKS);
412 void Print(FILE* out);
415 Object* GetValue() const {
416 if (lookup_type_ == DESCRIPTOR_TYPE) {
417 return GetValueFromMap(holder()->map());
418 } else if (lookup_type_ == TRANSITION_TYPE) {
419 return GetValueFromMap(transition_);
421 // In the dictionary case, the data is held in the value field.
422 ASSERT(lookup_type_ == DICTIONARY_TYPE);
423 return holder()->GetNormalizedProperty(this);
426 Object* GetValueFromMap(Map* map) const {
427 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
428 lookup_type_ == TRANSITION_TYPE);
429 ASSERT(number_ < map->NumberOfOwnDescriptors());
430 return map->instance_descriptors()->GetValue(number_);
433 int GetFieldIndexFromMap(Map* map) const {
434 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
435 lookup_type_ == TRANSITION_TYPE);
436 ASSERT(number_ < map->NumberOfOwnDescriptors());
437 return map->instance_descriptors()->GetFieldIndex(number_);
440 HeapType* GetFieldType() const {
441 ASSERT(type() == FIELD);
442 if (lookup_type_ == DESCRIPTOR_TYPE) {
443 return GetFieldTypeFromMap(holder()->map());
445 ASSERT(lookup_type_ == TRANSITION_TYPE);
446 return GetFieldTypeFromMap(transition_);
449 HeapType* GetFieldTypeFromMap(Map* map) const {
450 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
451 lookup_type_ == TRANSITION_TYPE);
452 ASSERT(number_ < map->NumberOfOwnDescriptors());
453 return map->instance_descriptors()->GetFieldType(number_);
456 Map* GetFieldOwner() const {
457 return GetFieldOwnerFromMap(holder()->map());
460 Map* GetFieldOwnerFromMap(Map* map) const {
461 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
462 lookup_type_ == TRANSITION_TYPE);
463 ASSERT(number_ < map->NumberOfOwnDescriptors());
464 return map->FindFieldOwner(number_);
467 void Iterate(ObjectVisitor* visitor);
473 // Where did we find the result;
487 PropertyDetails details_;
490 } } // namespace v8::internal
492 #endif // V8_PROPERTY_H_