1// Copyright 2006-2008 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
31namespace v8 {
32namespace internal {
33
34
35// Abstraction for elements in instance-descriptor arrays.
36//
37// Each descriptor has a key, property attributes, property type,
38// property index (in the actual instance-descriptor array) and
39// optionally a piece of data.
40//
41
42class Descriptor BASE_EMBEDDED {
43 public:
44  static int IndexFromValue(Object* value) {
45    return Smi::cast(value)->value();
46  }
47
48  MUST_USE_RESULT MaybeObject* KeyToSymbol() {
49    if (!StringShape(key_).IsSymbol()) {
50      Object* result;
51      { MaybeObject* maybe_result = HEAP->LookupSymbol(key_);
52        if (!maybe_result->ToObject(&result)) return maybe_result;
53      }
54      key_ = String::cast(result);
55    }
56    return key_;
57  }
58
59  String* GetKey() { return key_; }
60  Object* GetValue() { return value_; }
61  PropertyDetails GetDetails() { return details_; }
62
63#ifdef OBJECT_PRINT
64  void Print(FILE* out);
65#endif
66
67  void SetEnumerationIndex(int index) {
68    ASSERT(PropertyDetails::IsValidIndex(index));
69    details_ = PropertyDetails(details_.attributes(), details_.type(), index);
70  }
71
72 private:
73  String* key_;
74  Object* value_;
75  PropertyDetails details_;
76
77 protected:
78  Descriptor() : details_(Smi::FromInt(0)) {}
79
80  void Init(String* key, Object* value, PropertyDetails details) {
81    key_ = key;
82    value_ = value;
83    details_ = details;
84  }
85
86  Descriptor(String* key, Object* value, PropertyDetails details)
87      : key_(key),
88        value_(value),
89        details_(details) { }
90
91  Descriptor(String* key,
92             Object* value,
93             PropertyAttributes attributes,
94             PropertyType type,
95             int index = 0)
96      : key_(key),
97        value_(value),
98        details_(attributes, type, index) { }
99
100  friend class DescriptorArray;
101};
102
103// A pointer from a map to the new map that is created by adding
104// a named property.  These are key to the speed and functioning of V8.
105// The two maps should always have the same prototype, since
106// MapSpace::CreateBackPointers depends on this.
107class MapTransitionDescriptor: public Descriptor {
108 public:
109  MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
110      : Descriptor(key, map, attributes, MAP_TRANSITION) { }
111};
112
113class ExternalArrayTransitionDescriptor: public Descriptor {
114 public:
115  ExternalArrayTransitionDescriptor(String* key,
116                                    Map* map,
117                                    ExternalArrayType array_type)
118      : Descriptor(key, map, PropertyDetails(NONE,
119                                             EXTERNAL_ARRAY_TRANSITION,
120                                             array_type)) { }
121};
122
123// Marks a field name in a map so that adding the field is guaranteed
124// to create a FIELD descriptor in the new map.  Used after adding
125// a constant function the first time, creating a CONSTANT_FUNCTION
126// descriptor in the new map.  This avoids creating multiple maps with
127// the same CONSTANT_FUNCTION field.
128class ConstTransitionDescriptor: public Descriptor {
129 public:
130  explicit ConstTransitionDescriptor(String* key, Map* map)
131      : Descriptor(key, map, NONE, CONSTANT_TRANSITION) { }
132};
133
134
135class FieldDescriptor: public Descriptor {
136 public:
137  FieldDescriptor(String* key,
138                  int field_index,
139                  PropertyAttributes attributes,
140                  int index = 0)
141      : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {}
142};
143
144
145class ConstantFunctionDescriptor: public Descriptor {
146 public:
147  ConstantFunctionDescriptor(String* key,
148                             JSFunction* function,
149                             PropertyAttributes attributes,
150                             int index = 0)
151      : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
152};
153
154
155class CallbacksDescriptor:  public Descriptor {
156 public:
157  CallbacksDescriptor(String* key,
158                      Object* proxy,
159                      PropertyAttributes attributes,
160                      int index = 0)
161      : Descriptor(key, proxy, attributes, CALLBACKS, index) {}
162};
163
164
165class LookupResult BASE_EMBEDDED {
166 public:
167  // Where did we find the result;
168  enum {
169    NOT_FOUND,
170    DESCRIPTOR_TYPE,
171    DICTIONARY_TYPE,
172    INTERCEPTOR_TYPE,
173    CONSTANT_TYPE
174  } lookup_type_;
175
176  LookupResult()
177      : lookup_type_(NOT_FOUND),
178        cacheable_(true),
179        details_(NONE, NORMAL) {}
180
181  void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
182    lookup_type_ = DESCRIPTOR_TYPE;
183    holder_ = holder;
184    details_ = details;
185    number_ = number;
186  }
187
188  void DescriptorResult(JSObject* holder, Smi* details, int number) {
189    lookup_type_ = DESCRIPTOR_TYPE;
190    holder_ = holder;
191    details_ = PropertyDetails(details);
192    number_ = number;
193  }
194
195  void ConstantResult(JSObject* holder) {
196    lookup_type_ = CONSTANT_TYPE;
197    holder_ = holder;
198    details_ =
199        PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM |
200                                                        DONT_DELETE),
201                        CALLBACKS);
202    number_ = -1;
203  }
204
205  void DictionaryResult(JSObject* holder, int entry) {
206    lookup_type_ = DICTIONARY_TYPE;
207    holder_ = holder;
208    details_ = holder->property_dictionary()->DetailsAt(entry);
209    number_ = entry;
210  }
211
212  void InterceptorResult(JSObject* holder) {
213    lookup_type_ = INTERCEPTOR_TYPE;
214    holder_ = holder;
215    details_ = PropertyDetails(NONE, INTERCEPTOR);
216  }
217
218  void NotFound() {
219    lookup_type_ = NOT_FOUND;
220  }
221
222  JSObject* holder() {
223    ASSERT(IsFound());
224    return holder_;
225  }
226
227  PropertyType type() {
228    ASSERT(IsFound());
229    return details_.type();
230  }
231
232  PropertyAttributes GetAttributes() {
233    ASSERT(IsFound());
234    return details_.attributes();
235  }
236
237  PropertyDetails GetPropertyDetails() {
238    return details_;
239  }
240
241  bool IsReadOnly() { return details_.IsReadOnly(); }
242  bool IsDontDelete() { return details_.IsDontDelete(); }
243  bool IsDontEnum() { return details_.IsDontEnum(); }
244  bool IsDeleted() { return details_.IsDeleted(); }
245  bool IsFound() { return lookup_type_ != NOT_FOUND; }
246
247  // Is the result is a property excluding transitions and the null
248  // descriptor?
249  bool IsProperty() {
250    return IsFound() && (type() < FIRST_PHANTOM_PROPERTY_TYPE);
251  }
252
253  // Is the result a property or a transition?
254  bool IsPropertyOrTransition() {
255    return IsFound() && (type() != NULL_DESCRIPTOR);
256  }
257
258  bool IsCacheable() { return cacheable_; }
259  void DisallowCaching() { cacheable_ = false; }
260
261  Object* GetLazyValue() {
262    switch (type()) {
263      case FIELD:
264        return holder()->FastPropertyAt(GetFieldIndex());
265      case NORMAL: {
266        Object* value;
267        value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
268        if (holder()->IsGlobalObject()) {
269          value = JSGlobalPropertyCell::cast(value)->value();
270        }
271        return value;
272      }
273      case CONSTANT_FUNCTION:
274        return GetConstantFunction();
275      default:
276        return Smi::FromInt(0);
277    }
278  }
279
280  Map* GetTransitionMap() {
281    ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
282    ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION ||
283           type() == EXTERNAL_ARRAY_TRANSITION);
284    return Map::cast(GetValue());
285  }
286
287  Map* GetTransitionMapFromMap(Map* map) {
288    ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
289    ASSERT(type() == MAP_TRANSITION);
290    return Map::cast(map->instance_descriptors()->GetValue(number_));
291  }
292
293  int GetFieldIndex() {
294    ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
295    ASSERT(type() == FIELD);
296    return Descriptor::IndexFromValue(GetValue());
297  }
298
299  int GetLocalFieldIndexFromMap(Map* map) {
300    ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
301    ASSERT(type() == FIELD);
302    return Descriptor::IndexFromValue(
303        map->instance_descriptors()->GetValue(number_)) -
304        map->inobject_properties();
305  }
306
307  int GetDictionaryEntry() {
308    ASSERT(lookup_type_ == DICTIONARY_TYPE);
309    return number_;
310  }
311
312  JSFunction* GetConstantFunction() {
313    ASSERT(type() == CONSTANT_FUNCTION);
314    return JSFunction::cast(GetValue());
315  }
316
317  JSFunction* GetConstantFunctionFromMap(Map* map) {
318    ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
319    ASSERT(type() == CONSTANT_FUNCTION);
320    return JSFunction::cast(map->instance_descriptors()->GetValue(number_));
321  }
322
323  Object* GetCallbackObject() {
324    if (lookup_type_ == CONSTANT_TYPE) {
325      // For now we only have the __proto__ as constant type.
326      return HEAP->prototype_accessors();
327    }
328    return GetValue();
329  }
330
331#ifdef OBJECT_PRINT
332  void Print(FILE* out);
333#endif
334
335  Object* GetValue() {
336    if (lookup_type_ == DESCRIPTOR_TYPE) {
337      DescriptorArray* descriptors = holder()->map()->instance_descriptors();
338      return descriptors->GetValue(number_);
339    }
340    // In the dictionary case, the data is held in the value field.
341    ASSERT(lookup_type_ == DICTIONARY_TYPE);
342    return holder()->GetNormalizedProperty(this);
343  }
344
345 private:
346  JSObject* holder_;
347  int number_;
348  bool cacheable_;
349  PropertyDetails details_;
350};
351
352
353} }  // namespace v8::internal
354
355#endif  // V8_PROPERTY_H_
356