• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef V8_PROPERTY_H_
6 #define V8_PROPERTY_H_
7 
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"
13 
14 namespace v8 {
15 namespace internal {
16 
17 // Abstraction for elements in instance-descriptor arrays.
18 //
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 {
23  public:
KeyToUniqueName()24   void KeyToUniqueName() {
25     if (!key_->IsUniqueName()) {
26       key_ = key_->GetIsolate()->factory()->InternalizeString(
27           Handle<String>::cast(key_));
28     }
29   }
30 
GetKey()31   Handle<Name> GetKey() { return key_; }
GetValue()32   Handle<Object> GetValue() { return value_; }
GetDetails()33   PropertyDetails GetDetails() { return details_; }
34 
35 #ifdef OBJECT_PRINT
36   void Print(FILE* out);
37 #endif
38 
SetSortedKeyIndex(int index)39   void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
40 
41  private:
42   Handle<Name> key_;
43   Handle<Object> value_;
44   PropertyDetails details_;
45 
46  protected:
Descriptor()47   Descriptor() : details_(Smi::FromInt(0)) {}
48 
Init(Handle<Name> key,Handle<Object> value,PropertyDetails details)49   void Init(Handle<Name> key, Handle<Object> value, PropertyDetails details) {
50     key_ = key;
51     value_ = value;
52     details_ = details;
53   }
54 
Descriptor(Handle<Name> key,Handle<Object> value,PropertyDetails details)55   Descriptor(Handle<Name> key, Handle<Object> value, PropertyDetails details)
56       : key_(key),
57         value_(value),
58         details_(details) { }
59 
60   Descriptor(Handle<Name> key,
61              Handle<Object> value,
62              PropertyAttributes attributes,
63              PropertyType type,
64              Representation representation,
65              int field_index = 0)
key_(key)66       : key_(key),
67         value_(value),
68         details_(attributes, type, representation, field_index) { }
69 
70   friend class DescriptorArray;
71   friend class Map;
72 };
73 
74 
75 class FieldDescriptor V8_FINAL : public Descriptor {
76  public:
FieldDescriptor(Handle<Name> key,int field_index,PropertyAttributes attributes,Representation representation)77   FieldDescriptor(Handle<Name> key,
78                   int field_index,
79                   PropertyAttributes attributes,
80                   Representation representation)
81       : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
82                    FIELD, representation, field_index) {}
FieldDescriptor(Handle<Name> key,int field_index,Handle<HeapType> field_type,PropertyAttributes attributes,Representation representation)83   FieldDescriptor(Handle<Name> key,
84                   int field_index,
85                   Handle<HeapType> field_type,
86                   PropertyAttributes attributes,
87                   Representation representation)
88       : Descriptor(key, field_type, attributes, FIELD,
89                    representation, field_index) { }
90 };
91 
92 
93 class ConstantDescriptor V8_FINAL : public Descriptor {
94  public:
ConstantDescriptor(Handle<Name> key,Handle<Object> value,PropertyAttributes attributes)95   ConstantDescriptor(Handle<Name> key,
96                      Handle<Object> value,
97                      PropertyAttributes attributes)
98       : Descriptor(key, value, attributes, CONSTANT,
99                    value->OptimalRepresentation()) {}
100 };
101 
102 
103 class CallbacksDescriptor V8_FINAL : public Descriptor {
104  public:
CallbacksDescriptor(Handle<Name> key,Handle<Object> foreign,PropertyAttributes attributes)105   CallbacksDescriptor(Handle<Name> key,
106                       Handle<Object> foreign,
107                       PropertyAttributes attributes)
108       : Descriptor(key, foreign, attributes, CALLBACKS,
109                    Representation::Tagged()) {}
110 };
111 
112 
113 class LookupResult V8_FINAL BASE_EMBEDDED {
114  public:
LookupResult(Isolate * isolate)115   explicit LookupResult(Isolate* isolate)
116       : isolate_(isolate),
117         next_(isolate->top_lookup_result()),
118         lookup_type_(NOT_FOUND),
119         holder_(NULL),
120         transition_(NULL),
121         cacheable_(true),
122         details_(NONE, NONEXISTENT, Representation::None()) {
123     isolate->set_top_lookup_result(this);
124   }
125 
~LookupResult()126   ~LookupResult() {
127     ASSERT(isolate()->top_lookup_result() == this);
128     isolate()->set_top_lookup_result(next_);
129   }
130 
isolate()131   Isolate* isolate() const { return isolate_; }
132 
DescriptorResult(JSObject * holder,PropertyDetails details,int number)133   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
134     lookup_type_ = DESCRIPTOR_TYPE;
135     holder_ = holder;
136     transition_ = NULL;
137     details_ = details;
138     number_ = number;
139   }
140 
CanHoldValue(Handle<Object> value)141   bool CanHoldValue(Handle<Object> value) const {
142     switch (type()) {
143       case NORMAL:
144         return true;
145       case FIELD:
146         return value->FitsRepresentation(representation()) &&
147             GetFieldType()->NowContains(value);
148       case CONSTANT:
149         ASSERT(GetConstant() != *value ||
150                value->FitsRepresentation(representation()));
151         return GetConstant() == *value;
152       case CALLBACKS:
153       case HANDLER:
154       case INTERCEPTOR:
155         return true;
156       case NONEXISTENT:
157         UNREACHABLE();
158     }
159     UNREACHABLE();
160     return true;
161   }
162 
TransitionResult(JSObject * holder,Map * target)163   void TransitionResult(JSObject* holder, Map* target) {
164     lookup_type_ = TRANSITION_TYPE;
165     number_ = target->LastAdded();
166     details_ = target->instance_descriptors()->GetDetails(number_);
167     holder_ = holder;
168     transition_ = target;
169   }
170 
DictionaryResult(JSObject * holder,int entry)171   void DictionaryResult(JSObject* holder, int entry) {
172     lookup_type_ = DICTIONARY_TYPE;
173     holder_ = holder;
174     transition_ = NULL;
175     details_ = holder->property_dictionary()->DetailsAt(entry);
176     number_ = entry;
177   }
178 
HandlerResult(JSProxy * proxy)179   void HandlerResult(JSProxy* proxy) {
180     lookup_type_ = HANDLER_TYPE;
181     holder_ = proxy;
182     transition_ = NULL;
183     details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
184     cacheable_ = false;
185   }
186 
InterceptorResult(JSObject * holder)187   void InterceptorResult(JSObject* holder) {
188     lookup_type_ = INTERCEPTOR_TYPE;
189     holder_ = holder;
190     transition_ = NULL;
191     details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
192   }
193 
NotFound()194   void NotFound() {
195     lookup_type_ = NOT_FOUND;
196     details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
197     holder_ = NULL;
198     transition_ = NULL;
199   }
200 
holder()201   JSObject* holder() const {
202     ASSERT(IsFound());
203     return JSObject::cast(holder_);
204   }
205 
proxy()206   JSProxy* proxy() const {
207     ASSERT(IsHandler());
208     return JSProxy::cast(holder_);
209   }
210 
type()211   PropertyType type() const {
212     ASSERT(IsFound());
213     return details_.type();
214   }
215 
representation()216   Representation representation() const {
217     ASSERT(IsFound());
218     ASSERT(details_.type() != NONEXISTENT);
219     return details_.representation();
220   }
221 
GetAttributes()222   PropertyAttributes GetAttributes() const {
223     ASSERT(IsFound());
224     ASSERT(details_.type() != NONEXISTENT);
225     return details_.attributes();
226   }
227 
GetPropertyDetails()228   PropertyDetails GetPropertyDetails() const {
229     return details_;
230   }
231 
IsFastPropertyType()232   bool IsFastPropertyType() const {
233     ASSERT(IsFound());
234     return IsTransition() || type() != NORMAL;
235   }
236 
237   // Property callbacks does not include transitions to callbacks.
IsPropertyCallbacks()238   bool IsPropertyCallbacks() const {
239     ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
240     return !IsTransition() && details_.type() == CALLBACKS;
241   }
242 
IsReadOnly()243   bool IsReadOnly() const {
244     ASSERT(IsFound());
245     ASSERT(details_.type() != NONEXISTENT);
246     return details_.IsReadOnly();
247   }
248 
IsField()249   bool IsField() const {
250     ASSERT(!(details_.type() == FIELD && !IsFound()));
251     return IsDescriptorOrDictionary() && type() == FIELD;
252   }
253 
IsNormal()254   bool IsNormal() const {
255     ASSERT(!(details_.type() == NORMAL && !IsFound()));
256     return IsDescriptorOrDictionary() && type() == NORMAL;
257   }
258 
IsConstant()259   bool IsConstant() const {
260     ASSERT(!(details_.type() == CONSTANT && !IsFound()));
261     return IsDescriptorOrDictionary() && type() == CONSTANT;
262   }
263 
IsConstantFunction()264   bool IsConstantFunction() const {
265     return IsConstant() && GetConstant()->IsJSFunction();
266   }
267 
IsDontDelete()268   bool IsDontDelete() const { return details_.IsDontDelete(); }
IsDontEnum()269   bool IsDontEnum() const { return details_.IsDontEnum(); }
IsFound()270   bool IsFound() const { return lookup_type_ != NOT_FOUND; }
IsDescriptorOrDictionary()271   bool IsDescriptorOrDictionary() const {
272     return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE;
273   }
IsTransition()274   bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
IsHandler()275   bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; }
IsInterceptor()276   bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; }
277 
278   // Is the result is a property excluding transitions and the null descriptor?
IsProperty()279   bool IsProperty() const {
280     return IsFound() && !IsTransition();
281   }
282 
IsDataProperty()283   bool IsDataProperty() const {
284     switch (lookup_type_) {
285       case NOT_FOUND:
286       case TRANSITION_TYPE:
287       case HANDLER_TYPE:
288       case INTERCEPTOR_TYPE:
289         return false;
290 
291       case DESCRIPTOR_TYPE:
292       case DICTIONARY_TYPE:
293         switch (type()) {
294           case FIELD:
295           case NORMAL:
296           case CONSTANT:
297             return true;
298           case CALLBACKS: {
299             Object* callback = GetCallbackObject();
300             ASSERT(!callback->IsForeign());
301             return callback->IsAccessorInfo();
302           }
303           case HANDLER:
304           case INTERCEPTOR:
305           case NONEXISTENT:
306             UNREACHABLE();
307             return false;
308         }
309     }
310     UNREACHABLE();
311     return false;
312   }
313 
IsCacheable()314   bool IsCacheable() const { return cacheable_; }
DisallowCaching()315   void DisallowCaching() { cacheable_ = false; }
316 
GetLazyValue()317   Object* GetLazyValue() const {
318     switch (lookup_type_) {
319       case NOT_FOUND:
320       case TRANSITION_TYPE:
321       case HANDLER_TYPE:
322       case INTERCEPTOR_TYPE:
323         return isolate()->heap()->the_hole_value();
324 
325       case DESCRIPTOR_TYPE:
326       case DICTIONARY_TYPE:
327         switch (type()) {
328           case FIELD:
329             return holder()->RawFastPropertyAt(GetFieldIndex());
330           case NORMAL: {
331             Object* value = holder()->property_dictionary()->ValueAt(
332                 GetDictionaryEntry());
333             if (holder()->IsGlobalObject()) {
334               value = PropertyCell::cast(value)->value();
335             }
336             return value;
337           }
338           case CONSTANT:
339             return GetConstant();
340           case CALLBACKS:
341             return isolate()->heap()->the_hole_value();
342           case HANDLER:
343           case INTERCEPTOR:
344           case NONEXISTENT:
345             UNREACHABLE();
346             return NULL;
347         }
348     }
349     UNREACHABLE();
350     return NULL;
351   }
352 
GetTransitionTarget()353   Map* GetTransitionTarget() const {
354     ASSERT(IsTransition());
355     return transition_;
356   }
357 
IsTransitionToField()358   bool IsTransitionToField() const {
359     return IsTransition() && details_.type() == FIELD;
360   }
361 
IsTransitionToConstant()362   bool IsTransitionToConstant() const {
363     return IsTransition() && details_.type() == CONSTANT;
364   }
365 
GetDescriptorIndex()366   int GetDescriptorIndex() const {
367     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
368     return number_;
369   }
370 
GetFieldIndex()371   FieldIndex GetFieldIndex() const {
372     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
373            lookup_type_ == TRANSITION_TYPE);
374     return FieldIndex::ForLookupResult(this);
375   }
376 
GetLocalFieldIndexFromMap(Map * map)377   int GetLocalFieldIndexFromMap(Map* map) const {
378     return GetFieldIndexFromMap(map) - map->inobject_properties();
379   }
380 
GetDictionaryEntry()381   int GetDictionaryEntry() const {
382     ASSERT(lookup_type_ == DICTIONARY_TYPE);
383     return number_;
384   }
385 
GetConstantFunction()386   JSFunction* GetConstantFunction() const {
387     ASSERT(type() == CONSTANT);
388     return JSFunction::cast(GetValue());
389   }
390 
GetConstantFromMap(Map * map)391   Object* GetConstantFromMap(Map* map) const {
392     ASSERT(type() == CONSTANT);
393     return GetValueFromMap(map);
394   }
395 
GetConstantFunctionFromMap(Map * map)396   JSFunction* GetConstantFunctionFromMap(Map* map) const {
397     return JSFunction::cast(GetConstantFromMap(map));
398   }
399 
GetConstant()400   Object* GetConstant() const {
401     ASSERT(type() == CONSTANT);
402     return GetValue();
403   }
404 
GetCallbackObject()405   Object* GetCallbackObject() const {
406     ASSERT(!IsTransition());
407     ASSERT(type() == CALLBACKS);
408     return GetValue();
409   }
410 
411 #ifdef OBJECT_PRINT
412   void Print(FILE* out);
413 #endif
414 
GetValue()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_);
420     }
421     // In the dictionary case, the data is held in the value field.
422     ASSERT(lookup_type_ == DICTIONARY_TYPE);
423     return holder()->GetNormalizedProperty(this);
424   }
425 
GetValueFromMap(Map * map)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_);
431   }
432 
GetFieldIndexFromMap(Map * map)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_);
438   }
439 
GetFieldType()440   HeapType* GetFieldType() const {
441     ASSERT(type() == FIELD);
442     if (lookup_type_ == DESCRIPTOR_TYPE) {
443       return GetFieldTypeFromMap(holder()->map());
444     }
445     ASSERT(lookup_type_ == TRANSITION_TYPE);
446     return GetFieldTypeFromMap(transition_);
447   }
448 
GetFieldTypeFromMap(Map * map)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_);
454   }
455 
GetFieldOwner()456   Map* GetFieldOwner() const {
457     return GetFieldOwnerFromMap(holder()->map());
458   }
459 
GetFieldOwnerFromMap(Map * 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_);
465   }
466 
467   void Iterate(ObjectVisitor* visitor);
468 
469  private:
470   Isolate* isolate_;
471   LookupResult* next_;
472 
473   // Where did we find the result;
474   enum {
475     NOT_FOUND,
476     DESCRIPTOR_TYPE,
477     TRANSITION_TYPE,
478     DICTIONARY_TYPE,
479     HANDLER_TYPE,
480     INTERCEPTOR_TYPE
481   } lookup_type_;
482 
483   JSReceiver* holder_;
484   Map* transition_;
485   int number_;
486   bool cacheable_;
487   PropertyDetails details_;
488 };
489 
490 } }  // namespace v8::internal
491 
492 #endif  // V8_PROPERTY_H_
493