• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_PROPERTY_H_
29 #define V8_PROPERTY_H_
30 
31 #include "allocation.h"
32 #include "transitions.h"
33 
34 namespace v8 {
35 namespace internal {
36 
37 
38 // Abstraction for elements in instance-descriptor arrays.
39 //
40 // Each descriptor has a key, property attributes, property type,
41 // property index (in the actual instance-descriptor array) and
42 // optionally a piece of data.
43 //
44 
45 class Descriptor BASE_EMBEDDED {
46  public:
KeyToUniqueName()47   MUST_USE_RESULT MaybeObject* KeyToUniqueName() {
48     if (!key_->IsUniqueName()) {
49       MaybeObject* maybe_result =
50           key_->GetIsolate()->heap()->InternalizeString(String::cast(key_));
51       if (!maybe_result->To(&key_)) return maybe_result;
52     }
53     return key_;
54   }
55 
GetKey()56   Name* GetKey() { return key_; }
GetValue()57   Object* GetValue() { return value_; }
GetDetails()58   PropertyDetails GetDetails() { return details_; }
59 
60 #ifdef OBJECT_PRINT
61   void Print(FILE* out);
62 #endif
63 
SetSortedKeyIndex(int index)64   void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
65 
66  private:
67   Name* key_;
68   Object* value_;
69   PropertyDetails details_;
70 
71  protected:
Descriptor()72   Descriptor() : details_(Smi::FromInt(0)) {}
73 
Init(Name * key,Object * value,PropertyDetails details)74   void Init(Name* key, Object* value, PropertyDetails details) {
75     key_ = key;
76     value_ = value;
77     details_ = details;
78   }
79 
Descriptor(Name * key,Object * value,PropertyDetails details)80   Descriptor(Name* key, Object* value, PropertyDetails details)
81       : key_(key),
82         value_(value),
83         details_(details) { }
84 
85   Descriptor(Name* key,
86              Object* value,
87              PropertyAttributes attributes,
88              PropertyType type,
89              Representation representation,
90              int field_index = 0)
key_(key)91       : key_(key),
92         value_(value),
93         details_(attributes, type, representation, field_index) { }
94 
95   friend class DescriptorArray;
96 };
97 
98 
99 class FieldDescriptor: public Descriptor {
100  public:
FieldDescriptor(Name * key,int field_index,PropertyAttributes attributes,Representation representation)101   FieldDescriptor(Name* key,
102                   int field_index,
103                   PropertyAttributes attributes,
104                   Representation representation)
105       : Descriptor(key, Smi::FromInt(0), attributes,
106                    FIELD, representation, field_index) {}
107 };
108 
109 
110 class ConstantDescriptor: public Descriptor {
111  public:
ConstantDescriptor(Name * key,Object * value,PropertyAttributes attributes)112   ConstantDescriptor(Name* key,
113                      Object* value,
114                      PropertyAttributes attributes)
115       : Descriptor(key, value, attributes, CONSTANT,
116                    value->OptimalRepresentation()) {}
117 };
118 
119 
120 class CallbacksDescriptor:  public Descriptor {
121  public:
CallbacksDescriptor(Name * key,Object * foreign,PropertyAttributes attributes)122   CallbacksDescriptor(Name* key,
123                       Object* foreign,
124                       PropertyAttributes attributes)
125       : Descriptor(key, foreign, attributes, CALLBACKS,
126                    Representation::Tagged()) {}
127 };
128 
129 
130 // Holds a property index value distinguishing if it is a field index or an
131 // index inside the object header.
132 class PropertyIndex {
133  public:
NewFieldIndex(int index)134   static PropertyIndex NewFieldIndex(int index) {
135     return PropertyIndex(index, false);
136   }
NewHeaderIndex(int index)137   static PropertyIndex NewHeaderIndex(int index) {
138     return PropertyIndex(index, true);
139   }
140 
is_field_index()141   bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; }
is_header_index()142   bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; }
143 
field_index()144   int field_index() {
145     ASSERT(is_field_index());
146     return value();
147   }
header_index()148   int header_index() {
149     ASSERT(is_header_index());
150     return value();
151   }
152 
is_inobject(Handle<JSObject> holder)153   bool is_inobject(Handle<JSObject> holder) {
154     if (is_header_index()) return true;
155     return field_index() < holder->map()->inobject_properties();
156   }
157 
translate(Handle<JSObject> holder)158   int translate(Handle<JSObject> holder) {
159     if (is_header_index()) return header_index();
160     int index = field_index() - holder->map()->inobject_properties();
161     if (index >= 0) return index;
162     return index + holder->map()->instance_size() / kPointerSize;
163   }
164 
165  private:
166   static const int kHeaderIndexBit = 1 << 31;
167   static const int kIndexMask = ~kHeaderIndexBit;
168 
value()169   int value() { return index_ & kIndexMask; }
170 
PropertyIndex(int index,bool is_header_based)171   PropertyIndex(int index, bool is_header_based)
172       : index_(index | (is_header_based ? kHeaderIndexBit : 0)) {
173     ASSERT(index <= kIndexMask);
174   }
175 
176   int index_;
177 };
178 
179 
180 class LookupResult BASE_EMBEDDED {
181  public:
LookupResult(Isolate * isolate)182   explicit LookupResult(Isolate* isolate)
183       : isolate_(isolate),
184         next_(isolate->top_lookup_result()),
185         lookup_type_(NOT_FOUND),
186         holder_(NULL),
187         transition_(NULL),
188         cacheable_(true),
189         details_(NONE, NONEXISTENT, Representation::None()) {
190     isolate->SetTopLookupResult(this);
191   }
192 
~LookupResult()193   ~LookupResult() {
194     ASSERT(isolate()->top_lookup_result() == this);
195     isolate()->SetTopLookupResult(next_);
196   }
197 
isolate()198   Isolate* isolate() const { return isolate_; }
199 
DescriptorResult(JSObject * holder,PropertyDetails details,int number)200   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
201     lookup_type_ = DESCRIPTOR_TYPE;
202     holder_ = holder;
203     details_ = details;
204     number_ = number;
205     transition_ = NULL;
206   }
207 
CanHoldValue(Handle<Object> value)208   bool CanHoldValue(Handle<Object> value) {
209     if (IsNormal()) return true;
210     ASSERT(!IsTransition());
211     return value->FitsRepresentation(details_.representation());
212   }
213 
TransitionResult(JSObject * holder,Map * target)214   void TransitionResult(JSObject* holder, Map* target) {
215     lookup_type_ = TRANSITION_TYPE;
216     details_ = PropertyDetails(NONE, TRANSITION, Representation::None());
217     holder_ = holder;
218     transition_ = target;
219     number_ = 0xAAAA;
220   }
221 
DictionaryResult(JSObject * holder,int entry)222   void DictionaryResult(JSObject* holder, int entry) {
223     lookup_type_ = DICTIONARY_TYPE;
224     holder_ = holder;
225     transition_ = NULL;
226     details_ = holder->property_dictionary()->DetailsAt(entry);
227     number_ = entry;
228   }
229 
HandlerResult(JSProxy * proxy)230   void HandlerResult(JSProxy* proxy) {
231     lookup_type_ = HANDLER_TYPE;
232     holder_ = proxy;
233     transition_ = NULL;
234     details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
235     cacheable_ = false;
236   }
237 
InterceptorResult(JSObject * holder)238   void InterceptorResult(JSObject* holder) {
239     lookup_type_ = INTERCEPTOR_TYPE;
240     holder_ = holder;
241     transition_ = NULL;
242     details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
243   }
244 
NotFound()245   void NotFound() {
246     lookup_type_ = NOT_FOUND;
247     details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
248     holder_ = NULL;
249   }
250 
holder()251   JSObject* holder() {
252     ASSERT(IsFound());
253     return JSObject::cast(holder_);
254   }
255 
proxy()256   JSProxy* proxy() {
257     ASSERT(IsHandler());
258     return JSProxy::cast(holder_);
259   }
260 
type()261   PropertyType type() {
262     ASSERT(IsFound());
263     return details_.type();
264   }
265 
representation()266   Representation representation() {
267     ASSERT(IsFound());
268     ASSERT(!IsTransition());
269     ASSERT(details_.type() != NONEXISTENT);
270     return details_.representation();
271   }
272 
GetAttributes()273   PropertyAttributes GetAttributes() {
274     ASSERT(!IsTransition());
275     ASSERT(IsFound());
276     ASSERT(details_.type() != NONEXISTENT);
277     return details_.attributes();
278   }
279 
GetPropertyDetails()280   PropertyDetails GetPropertyDetails() {
281     ASSERT(!IsTransition());
282     return details_;
283   }
284 
IsFastPropertyType()285   bool IsFastPropertyType() {
286     ASSERT(IsFound());
287     return IsTransition() || type() != NORMAL;
288   }
289 
290   // Property callbacks does not include transitions to callbacks.
IsPropertyCallbacks()291   bool IsPropertyCallbacks() {
292     ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
293     return details_.type() == CALLBACKS;
294   }
295 
IsReadOnly()296   bool IsReadOnly() {
297     ASSERT(IsFound());
298     ASSERT(!IsTransition());
299     ASSERT(details_.type() != NONEXISTENT);
300     return details_.IsReadOnly();
301   }
302 
IsField()303   bool IsField() {
304     ASSERT(!(details_.type() == FIELD && !IsFound()));
305     return details_.type() == FIELD;
306   }
307 
IsNormal()308   bool IsNormal() {
309     ASSERT(!(details_.type() == NORMAL && !IsFound()));
310     return details_.type() == NORMAL;
311   }
312 
IsConstant()313   bool IsConstant() {
314     ASSERT(!(details_.type() == CONSTANT && !IsFound()));
315     return details_.type() == CONSTANT;
316   }
317 
IsConstantFunction()318   bool IsConstantFunction() {
319     return IsConstant() && GetValue()->IsJSFunction();
320   }
321 
IsDontDelete()322   bool IsDontDelete() { return details_.IsDontDelete(); }
IsDontEnum()323   bool IsDontEnum() { return details_.IsDontEnum(); }
IsFound()324   bool IsFound() { return lookup_type_ != NOT_FOUND; }
IsTransition()325   bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; }
IsHandler()326   bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
IsInterceptor()327   bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; }
328 
329   // Is the result is a property excluding transitions and the null descriptor?
IsProperty()330   bool IsProperty() {
331     return IsFound() && !IsTransition();
332   }
333 
IsDataProperty()334   bool IsDataProperty() {
335     switch (type()) {
336       case FIELD:
337       case NORMAL:
338       case CONSTANT:
339         return true;
340       case CALLBACKS: {
341         Object* callback = GetCallbackObject();
342         return callback->IsAccessorInfo() || callback->IsForeign();
343       }
344       case HANDLER:
345       case INTERCEPTOR:
346       case TRANSITION:
347       case NONEXISTENT:
348         return false;
349     }
350     UNREACHABLE();
351     return false;
352   }
353 
IsCacheable()354   bool IsCacheable() { return cacheable_; }
DisallowCaching()355   void DisallowCaching() { cacheable_ = false; }
356 
GetLazyValue()357   Object* GetLazyValue() {
358     switch (type()) {
359       case FIELD:
360         return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
361       case NORMAL: {
362         Object* value;
363         value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
364         if (holder()->IsGlobalObject()) {
365           value = PropertyCell::cast(value)->value();
366         }
367         return value;
368       }
369       case CONSTANT:
370         return GetConstant();
371       case CALLBACKS:
372       case HANDLER:
373       case INTERCEPTOR:
374       case TRANSITION:
375       case NONEXISTENT:
376         return isolate()->heap()->the_hole_value();
377     }
378     UNREACHABLE();
379     return NULL;
380   }
381 
GetTransitionTarget()382   Map* GetTransitionTarget() {
383     return transition_;
384   }
385 
GetTransitionDetails()386   PropertyDetails GetTransitionDetails() {
387     return transition_->GetLastDescriptorDetails();
388   }
389 
IsTransitionToField()390   bool IsTransitionToField() {
391     return IsTransition() && GetTransitionDetails().type() == FIELD;
392   }
393 
IsTransitionToConstant()394   bool IsTransitionToConstant() {
395     return IsTransition() && GetTransitionDetails().type() == CONSTANT;
396   }
397 
GetTransitionIndex()398   int GetTransitionIndex() {
399     ASSERT(IsTransition());
400     return number_;
401   }
402 
GetDescriptorIndex()403   int GetDescriptorIndex() {
404     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
405     return number_;
406   }
407 
GetFieldIndex()408   PropertyIndex GetFieldIndex() {
409     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
410     return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
411   }
412 
GetLocalFieldIndexFromMap(Map * map)413   int GetLocalFieldIndexFromMap(Map* map) {
414     return GetFieldIndexFromMap(map) - map->inobject_properties();
415   }
416 
GetDictionaryEntry()417   int GetDictionaryEntry() {
418     ASSERT(lookup_type_ == DICTIONARY_TYPE);
419     return number_;
420   }
421 
GetConstantFunction()422   JSFunction* GetConstantFunction() {
423     ASSERT(type() == CONSTANT);
424     return JSFunction::cast(GetValue());
425   }
426 
GetConstantFromMap(Map * map)427   Object* GetConstantFromMap(Map* map) {
428     ASSERT(type() == CONSTANT);
429     return GetValueFromMap(map);
430   }
431 
GetConstantFunctionFromMap(Map * map)432   JSFunction* GetConstantFunctionFromMap(Map* map) {
433     return JSFunction::cast(GetConstantFromMap(map));
434   }
435 
GetConstant()436   Object* GetConstant() {
437     ASSERT(type() == CONSTANT);
438     return GetValue();
439   }
440 
GetCallbackObject()441   Object* GetCallbackObject() {
442     ASSERT(type() == CALLBACKS && !IsTransition());
443     return GetValue();
444   }
445 
446 #ifdef OBJECT_PRINT
447   void Print(FILE* out);
448 #endif
449 
GetValue()450   Object* GetValue() {
451     if (lookup_type_ == DESCRIPTOR_TYPE) {
452       return GetValueFromMap(holder()->map());
453     }
454     // In the dictionary case, the data is held in the value field.
455     ASSERT(lookup_type_ == DICTIONARY_TYPE);
456     return holder()->GetNormalizedProperty(this);
457   }
458 
GetValueFromMap(Map * map)459   Object* GetValueFromMap(Map* map) const {
460     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
461     ASSERT(number_ < map->NumberOfOwnDescriptors());
462     return map->instance_descriptors()->GetValue(number_);
463   }
464 
GetFieldIndexFromMap(Map * map)465   int GetFieldIndexFromMap(Map* map) const {
466     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
467     ASSERT(number_ < map->NumberOfOwnDescriptors());
468     return map->instance_descriptors()->GetFieldIndex(number_);
469   }
470 
471   void Iterate(ObjectVisitor* visitor);
472 
473  private:
474   Isolate* isolate_;
475   LookupResult* next_;
476 
477   // Where did we find the result;
478   enum {
479     NOT_FOUND,
480     DESCRIPTOR_TYPE,
481     TRANSITION_TYPE,
482     DICTIONARY_TYPE,
483     HANDLER_TYPE,
484     INTERCEPTOR_TYPE
485   } lookup_type_;
486 
487   JSReceiver* holder_;
488   Map* transition_;
489   int number_;
490   bool cacheable_;
491   PropertyDetails details_;
492 };
493 
494 
495 } }  // namespace v8::internal
496 
497 #endif  // V8_PROPERTY_H_
498