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.
15 // Abstraction for elements in instance-descriptor arrays.
17 // Each descriptor has a key, property attributes, property type,
18 // property index (in the actual instance-descriptor array) and
19 // optionally a piece of data.
20 class Descriptor BASE_EMBEDDED {
22 void KeyToUniqueName() {
23 if (!key_->IsUniqueName()) {
24 key_ = key_->GetIsolate()->factory()->InternalizeString(
25 Handle<String>::cast(key_));
29 Handle<Name> GetKey() { return key_; }
30 Handle<Object> GetValue() { return value_; }
31 PropertyDetails GetDetails() { return details_; }
34 void Print(FILE* out);
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 class FieldDescriptor V8_FINAL : public Descriptor {
75 FieldDescriptor(Handle<Name> key,
77 PropertyAttributes attributes,
78 Representation representation)
79 : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
80 FIELD, representation, field_index) {}
81 FieldDescriptor(Handle<Name> key,
83 Handle<HeapType> field_type,
84 PropertyAttributes attributes,
85 Representation representation)
86 : Descriptor(key, field_type, attributes, FIELD,
87 representation, field_index) { }
91 class ConstantDescriptor V8_FINAL : public Descriptor {
93 ConstantDescriptor(Handle<Name> key,
95 PropertyAttributes attributes)
96 : Descriptor(key, value, attributes, CONSTANT,
97 value->OptimalRepresentation()) {}
101 class CallbacksDescriptor V8_FINAL : public Descriptor {
103 CallbacksDescriptor(Handle<Name> key,
104 Handle<Object> foreign,
105 PropertyAttributes attributes)
106 : Descriptor(key, foreign, attributes, CALLBACKS,
107 Representation::Tagged()) {}
111 // Holds a property index value distinguishing if it is a field index or an
112 // index inside the object header.
113 class PropertyIndex V8_FINAL {
115 static PropertyIndex NewFieldIndex(int index) {
116 return PropertyIndex(index, false);
118 static PropertyIndex NewHeaderIndex(int index) {
119 return PropertyIndex(index, true);
122 bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; }
123 bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; }
126 ASSERT(is_field_index());
130 ASSERT(is_header_index());
134 bool is_inobject(Handle<JSObject> holder) {
135 if (is_header_index()) return true;
136 return field_index() < holder->map()->inobject_properties();
139 int translate(Handle<JSObject> holder) {
140 if (is_header_index()) return header_index();
141 int index = field_index() - holder->map()->inobject_properties();
142 if (index >= 0) return index;
143 return index + holder->map()->instance_size() / kPointerSize;
147 static const int kHeaderIndexBit = 1 << 31;
148 static const int kIndexMask = ~kHeaderIndexBit;
150 int value() { return index_ & kIndexMask; }
152 PropertyIndex(int index, bool is_header_based)
153 : index_(index | (is_header_based ? kHeaderIndexBit : 0)) {
154 ASSERT(index <= kIndexMask);
161 class LookupResult V8_FINAL BASE_EMBEDDED {
163 explicit LookupResult(Isolate* isolate)
165 next_(isolate->top_lookup_result()),
166 lookup_type_(NOT_FOUND),
170 details_(NONE, NONEXISTENT, Representation::None()) {
171 isolate->set_top_lookup_result(this);
175 ASSERT(isolate()->top_lookup_result() == this);
176 isolate()->set_top_lookup_result(next_);
179 Isolate* isolate() const { return isolate_; }
181 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
182 lookup_type_ = DESCRIPTOR_TYPE;
189 bool CanHoldValue(Handle<Object> value) const {
194 return value->FitsRepresentation(representation()) &&
195 GetFieldType()->NowContains(value);
197 ASSERT(GetConstant() != *value ||
198 value->FitsRepresentation(representation()));
199 return GetConstant() == *value;
211 void TransitionResult(JSObject* holder, Map* target) {
212 lookup_type_ = TRANSITION_TYPE;
213 number_ = target->LastAdded();
214 details_ = target->instance_descriptors()->GetDetails(number_);
216 transition_ = target;
219 void DictionaryResult(JSObject* holder, int entry) {
220 lookup_type_ = DICTIONARY_TYPE;
223 details_ = holder->property_dictionary()->DetailsAt(entry);
227 void HandlerResult(JSProxy* proxy) {
228 lookup_type_ = HANDLER_TYPE;
231 details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
235 void InterceptorResult(JSObject* holder) {
236 lookup_type_ = INTERCEPTOR_TYPE;
239 details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
243 lookup_type_ = NOT_FOUND;
244 details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
249 JSObject* holder() const {
251 return JSObject::cast(holder_);
254 JSProxy* proxy() const {
256 return JSProxy::cast(holder_);
259 PropertyType type() const {
261 return details_.type();
264 Representation representation() const {
266 ASSERT(details_.type() != NONEXISTENT);
267 return details_.representation();
270 PropertyAttributes GetAttributes() const {
272 ASSERT(details_.type() != NONEXISTENT);
273 return details_.attributes();
276 PropertyDetails GetPropertyDetails() const {
280 bool IsFastPropertyType() const {
282 return IsTransition() || type() != NORMAL;
285 // Property callbacks does not include transitions to callbacks.
286 bool IsPropertyCallbacks() const {
287 ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
288 return !IsTransition() && details_.type() == CALLBACKS;
291 bool IsReadOnly() const {
293 ASSERT(details_.type() != NONEXISTENT);
294 return details_.IsReadOnly();
297 bool IsField() const {
298 ASSERT(!(details_.type() == FIELD && !IsFound()));
299 return IsDescriptorOrDictionary() && type() == FIELD;
302 bool IsNormal() const {
303 ASSERT(!(details_.type() == NORMAL && !IsFound()));
304 return IsDescriptorOrDictionary() && type() == NORMAL;
307 bool IsConstant() const {
308 ASSERT(!(details_.type() == CONSTANT && !IsFound()));
309 return IsDescriptorOrDictionary() && type() == CONSTANT;
312 bool IsConstantFunction() const {
313 return IsConstant() && GetConstant()->IsJSFunction();
316 bool IsDontDelete() const { return details_.IsDontDelete(); }
317 bool IsDontEnum() const { return details_.IsDontEnum(); }
318 bool IsFound() const { return lookup_type_ != NOT_FOUND; }
319 bool IsDescriptorOrDictionary() const {
320 return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE;
322 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
323 bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; }
324 bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; }
326 // Is the result is a property excluding transitions and the null descriptor?
327 bool IsProperty() const {
328 return IsFound() && !IsTransition();
331 bool IsDataProperty() const {
332 switch (lookup_type_) {
334 case TRANSITION_TYPE:
336 case INTERCEPTOR_TYPE:
339 case DESCRIPTOR_TYPE:
340 case DICTIONARY_TYPE:
347 Object* callback = GetCallbackObject();
348 ASSERT(!callback->IsForeign());
349 return callback->IsAccessorInfo();
362 bool IsCacheable() const { return cacheable_; }
363 void DisallowCaching() { cacheable_ = false; }
365 Object* GetLazyValue() const {
366 switch (lookup_type_) {
368 case TRANSITION_TYPE:
370 case INTERCEPTOR_TYPE:
371 return isolate()->heap()->the_hole_value();
373 case DESCRIPTOR_TYPE:
374 case DICTIONARY_TYPE:
377 return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
379 Object* value = holder()->property_dictionary()->ValueAt(
380 GetDictionaryEntry());
381 if (holder()->IsGlobalObject()) {
382 value = PropertyCell::cast(value)->value();
387 return GetConstant();
389 return isolate()->heap()->the_hole_value();
401 Map* GetTransitionTarget() const {
402 ASSERT(IsTransition());
406 bool IsTransitionToField() const {
407 return IsTransition() && details_.type() == FIELD;
410 bool IsTransitionToConstant() const {
411 return IsTransition() && details_.type() == CONSTANT;
414 int GetDescriptorIndex() const {
415 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
419 PropertyIndex GetFieldIndex() const {
420 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
421 lookup_type_ == TRANSITION_TYPE);
422 return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
425 int GetLocalFieldIndexFromMap(Map* map) const {
426 return GetFieldIndexFromMap(map) - map->inobject_properties();
429 int GetDictionaryEntry() const {
430 ASSERT(lookup_type_ == DICTIONARY_TYPE);
434 JSFunction* GetConstantFunction() const {
435 ASSERT(type() == CONSTANT);
436 return JSFunction::cast(GetValue());
439 Object* GetConstantFromMap(Map* map) const {
440 ASSERT(type() == CONSTANT);
441 return GetValueFromMap(map);
444 JSFunction* GetConstantFunctionFromMap(Map* map) const {
445 return JSFunction::cast(GetConstantFromMap(map));
448 Object* GetConstant() const {
449 ASSERT(type() == CONSTANT);
453 Object* GetCallbackObject() const {
454 ASSERT(!IsTransition());
455 ASSERT(type() == CALLBACKS);
460 void Print(FILE* out);
463 Object* GetValue() const {
464 if (lookup_type_ == DESCRIPTOR_TYPE) {
465 return GetValueFromMap(holder()->map());
466 } else if (lookup_type_ == TRANSITION_TYPE) {
467 return GetValueFromMap(transition_);
469 // In the dictionary case, the data is held in the value field.
470 ASSERT(lookup_type_ == DICTIONARY_TYPE);
471 return holder()->GetNormalizedProperty(this);
474 Object* GetValueFromMap(Map* map) const {
475 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
476 lookup_type_ == TRANSITION_TYPE);
477 ASSERT(number_ < map->NumberOfOwnDescriptors());
478 return map->instance_descriptors()->GetValue(number_);
481 int GetFieldIndexFromMap(Map* map) const {
482 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
483 lookup_type_ == TRANSITION_TYPE);
484 ASSERT(number_ < map->NumberOfOwnDescriptors());
485 return map->instance_descriptors()->GetFieldIndex(number_);
488 HeapType* GetFieldType() const {
489 ASSERT(type() == FIELD);
490 if (lookup_type_ == DESCRIPTOR_TYPE) {
491 return GetFieldTypeFromMap(holder()->map());
493 ASSERT(lookup_type_ == TRANSITION_TYPE);
494 return GetFieldTypeFromMap(transition_);
497 HeapType* GetFieldTypeFromMap(Map* map) const {
498 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
499 lookup_type_ == TRANSITION_TYPE);
500 ASSERT(number_ < map->NumberOfOwnDescriptors());
501 return map->instance_descriptors()->GetFieldType(number_);
504 Map* GetFieldOwner() const {
505 return GetFieldOwnerFromMap(holder()->map());
508 Map* GetFieldOwnerFromMap(Map* map) const {
509 ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
510 lookup_type_ == TRANSITION_TYPE);
511 ASSERT(number_ < map->NumberOfOwnDescriptors());
512 return map->FindFieldOwner(number_);
515 void Iterate(ObjectVisitor* visitor);
521 // Where did we find the result;
535 PropertyDetails details_;
538 } } // namespace v8::internal
540 #endif // V8_PROPERTY_H_