blob: 60a9b544deff24bfac8d8722b543b73af244b4ea [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 { namespace internal {
32
33
34// Abstraction for elements in instance-descriptor arrays.
35//
36// Each descriptor has a key, property attributes, property type,
37// property index (in the actual instance-descriptor array) and
38// optionally a piece of data.
39//
40
41class Descriptor BASE_EMBEDDED {
42 public:
43 static int IndexFromValue(Object* value) {
44 return Smi::cast(value)->value();
45 }
46
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047 Object* KeyToSymbol() {
ager@chromium.org870a0b62008-11-04 11:43:05 +000048 if (!StringShape(key_).IsSymbol()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049 Object* result = Heap::LookupSymbol(key_);
50 if (result->IsFailure()) return result;
51 key_ = String::cast(result);
52 }
53 return key_;
54 }
55
56 String* GetKey() { return key_; }
57 Object* GetValue() { return value_; }
58 PropertyDetails GetDetails() { return details_; }
59
60#ifdef DEBUG
61 void Print();
62#endif
63
64 void SetEnumerationIndex(int index) {
65 ASSERT(PropertyDetails::IsValidIndex(index));
66 details_ = PropertyDetails(details_.attributes(), details_.type(), index);
67 }
68
69 private:
70 String* key_;
71 Object* value_;
72 PropertyDetails details_;
73
74 protected:
75 Descriptor() : details_(Smi::FromInt(0)) {}
76
77 void Init(String* key, Object* value, PropertyDetails details) {
78 key_ = key;
79 value_ = value;
80 details_ = details;
81 }
82
83 Descriptor(String* key, Object* value, PropertyDetails details)
84 : key_(key),
85 value_(value),
86 details_(details) { }
87
88 Descriptor(String* key,
89 Object* value,
90 PropertyAttributes attributes,
91 PropertyType type,
92 int index = 0)
93 : key_(key),
94 value_(value),
95 details_(attributes, type, index) { }
96
97 friend class DescriptorWriter;
98 friend class DescriptorReader;
99 friend class DescriptorArray;
100};
101
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000102// A pointer from a map to the new map that is created by adding
103// a named property. These are key to the speed and functioning of V8.
104// The two maps should always have the same prototype, since
105// MapSpace::CreateBackPointers depends on this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106class MapTransitionDescriptor: public Descriptor {
107 public:
108 MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
109 : Descriptor(key, map, attributes, MAP_TRANSITION) { }
110};
111
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000112// Marks a field name in a map so that adding the field is guaranteed
113// to create a FIELD descriptor in the new map. Used after adding
114// a constant function the first time, creating a CONSTANT_FUNCTION
115// descriptor in the new map. This avoids creating multiple maps with
116// the same CONSTANT_FUNCTION field.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117class ConstTransitionDescriptor: public Descriptor {
118 public:
119 explicit ConstTransitionDescriptor(String* key)
120 : Descriptor(key, Smi::FromInt(0), NONE, CONSTANT_TRANSITION) { }
121};
122
123
124class FieldDescriptor: public Descriptor {
125 public:
126 FieldDescriptor(String* key,
127 int field_index,
128 PropertyAttributes attributes,
129 int index = 0)
130 : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {}
131};
132
133
134class ConstantFunctionDescriptor: public Descriptor {
135 public:
136 ConstantFunctionDescriptor(String* key,
137 JSFunction* function,
138 PropertyAttributes attributes,
139 int index = 0)
140 : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
141};
142
143
144class CallbacksDescriptor: public Descriptor {
145 public:
146 CallbacksDescriptor(String* key,
147 Object* proxy,
148 PropertyAttributes attributes,
149 int index = 0)
150 : Descriptor(key, proxy, attributes, CALLBACKS, index) {}
151};
152
153
154class LookupResult BASE_EMBEDDED {
155 public:
156 // Where did we find the result;
157 enum {
158 NOT_FOUND,
159 DESCRIPTOR_TYPE,
160 DICTIONARY_TYPE,
161 INTERCEPTOR_TYPE,
162 CONSTANT_TYPE
163 } lookup_type_;
164
165 LookupResult()
166 : lookup_type_(NOT_FOUND),
167 cacheable_(true),
168 details_(NONE, NORMAL) {}
169
170 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
171 lookup_type_ = DESCRIPTOR_TYPE;
172 holder_ = holder;
173 details_ = details;
174 number_ = number;
175 }
176
177 void ConstantResult(JSObject* holder) {
178 lookup_type_ = CONSTANT_TYPE;
179 holder_ = holder;
180 details_ =
181 PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM |
182 DONT_DELETE),
183 CALLBACKS);
184 number_ = -1;
185 }
186
187 void DictionaryResult(JSObject* holder, int entry) {
188 lookup_type_ = DICTIONARY_TYPE;
189 holder_ = holder;
190 details_ = holder->property_dictionary()->DetailsAt(entry);
191 number_ = entry;
192 }
193
194 void InterceptorResult(JSObject* holder) {
195 lookup_type_ = INTERCEPTOR_TYPE;
196 holder_ = holder;
197 details_ = PropertyDetails(NONE, INTERCEPTOR);
198 }
199
200 void NotFound() {
201 lookup_type_ = NOT_FOUND;
202 }
203
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 JSObject* holder() {
205 ASSERT(IsValid());
206 return holder_;
207 }
208
209 PropertyType type() {
210 ASSERT(IsValid());
211 return details_.type();
212 }
213
214 bool IsTransitionType() {
215 PropertyType t = type();
216 if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true;
217 return false;
218 }
219
220 PropertyAttributes GetAttributes() {
221 ASSERT(IsValid());
222 return details_.attributes();
223 }
224
225 PropertyDetails GetPropertyDetails() {
226 return details_;
227 }
228
229 bool IsReadOnly() { return details_.IsReadOnly(); }
230 bool IsDontDelete() { return details_.IsDontDelete(); }
231 bool IsDontEnum() { return details_.IsDontEnum(); }
232
233 bool IsValid() { return lookup_type_ != NOT_FOUND; }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000234 bool IsNotFound() { return lookup_type_ == NOT_FOUND; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235
236 // Tells whether the result is a property.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000237 // Excluding transitions and the null descriptor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238 bool IsProperty() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000239 return IsValid() && type() < FIRST_PHANTOM_PROPERTY_TYPE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 }
241
242 bool IsCacheable() { return cacheable_; }
243 void DisallowCaching() { cacheable_ = false; }
244
245 // Tells whether the value needs to be loaded.
246 bool IsLoaded() {
247 if (lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000248 Object* target = GetLazyValue();
249 return !target->IsJSObject() || JSObject::cast(target)->IsLoaded();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 }
251 return true;
252 }
253
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000254 Object* GetLazyValue() {
255 switch (type()) {
256 case FIELD:
257 return holder()->FastPropertyAt(GetFieldIndex());
258 case NORMAL:
259 return holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
260 case CONSTANT_FUNCTION:
261 return GetConstantFunction();
262 default:
263 return Smi::FromInt(0);
264 }
265 }
266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267 Map* GetTransitionMap() {
268 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
269 ASSERT(type() == MAP_TRANSITION);
270 return Map::cast(GetValue());
271 }
272
273 int GetFieldIndex() {
274 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
275 ASSERT(type() == FIELD);
276 return Descriptor::IndexFromValue(GetValue());
277 }
278
279 int GetDictionaryEntry() {
280 ASSERT(lookup_type_ == DICTIONARY_TYPE);
281 return number_;
282 }
283
284 JSFunction* GetConstantFunction() {
285 ASSERT(type() == CONSTANT_FUNCTION);
286 return JSFunction::cast(GetValue());
287 }
288
289 Object* GetCallbackObject() {
290 if (lookup_type_ == CONSTANT_TYPE) {
291 // For now we only have the __proto__ as constant type.
292 return Heap::prototype_accessors();
293 }
294 return GetValue();
295 }
296
297#ifdef DEBUG
298 void Print();
299#endif
300
301 Object* GetValue() {
302 if (lookup_type_ == DESCRIPTOR_TYPE) {
303 DescriptorArray* descriptors = holder()->map()->instance_descriptors();
304 return descriptors->GetValue(number_);
305 }
306 // In the dictionary case, the data is held in the value field.
307 ASSERT(lookup_type_ == DICTIONARY_TYPE);
308 return holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
309 }
310
311 private:
312 JSObject* holder_;
313 int number_;
314 bool cacheable_;
315 PropertyDetails details_;
316};
317
318
319// The DescriptorStream is an abstraction for iterating over a map's
320// instance descriptors.
321class DescriptorStream BASE_EMBEDDED {
322 public:
323 explicit DescriptorStream(DescriptorArray* descriptors, int pos) {
324 descriptors_ = descriptors;
325 pos_ = pos;
326 limit_ = descriptors_->number_of_descriptors();
327 }
328
329 // Tells whether we have reached the end of the steam.
330 bool eos() { return pos_ >= limit_; }
331
332 int next_position() { return pos_ + 1; }
333 void advance() { pos_ = next_position(); }
334
335 protected:
336 DescriptorArray* descriptors_;
337 int pos_; // Current position.
ager@chromium.org32912102009-01-16 10:38:43 +0000338 int limit_; // Limit for position.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339};
340
341
342class DescriptorReader: public DescriptorStream {
343 public:
344 explicit DescriptorReader(DescriptorArray* descriptors, int pos = 0)
345 : DescriptorStream(descriptors, pos) {}
346
347 String* GetKey() { return descriptors_->GetKey(pos_); }
348 Object* GetValue() { return descriptors_->GetValue(pos_); }
349 PropertyDetails GetDetails() {
350 return PropertyDetails(descriptors_->GetDetails(pos_));
351 }
352
353 int GetFieldIndex() { return Descriptor::IndexFromValue(GetValue()); }
354
355 bool IsDontEnum() { return GetDetails().IsDontEnum(); }
356
357 PropertyType type() { return GetDetails().type(); }
358
359 // Tells whether the type is a transition.
360 bool IsTransition() {
361 PropertyType t = type();
362 ASSERT(t != INTERCEPTOR);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000363 return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
364 }
365
366 bool IsNullDescriptor() {
367 return type() == NULL_DESCRIPTOR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 }
369
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000370 bool IsProperty() {
371 return type() < FIRST_PHANTOM_PROPERTY_TYPE;
372 }
373
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 JSFunction* GetConstantFunction() { return JSFunction::cast(GetValue()); }
375
376 AccessorDescriptor* GetCallbacks() {
377 ASSERT(type() == CALLBACKS);
378 Proxy* p = Proxy::cast(GetCallbacksObject());
379 return reinterpret_cast<AccessorDescriptor*>(p->proxy());
380 }
381
382 Object* GetCallbacksObject() {
383 ASSERT(type() == CALLBACKS);
384 return GetValue();
385 }
386
387 bool Equals(String* name) { return name->Equals(GetKey()); }
388
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 void Get(Descriptor* desc) {
390 descriptors_->Get(pos_, desc);
391 }
392};
393
394class DescriptorWriter: public DescriptorStream {
395 public:
396 explicit DescriptorWriter(DescriptorArray* descriptors)
397 : DescriptorStream(descriptors, 0) {}
398
399 // Append a descriptor to this stream.
400 void Write(Descriptor* desc);
401 // Read a descriptor from the reader and append it to this stream.
402 void WriteFrom(DescriptorReader* reader);
403};
404
405} } // namespace v8::internal
406
407#endif // V8_PROPERTY_H_