blob: a94754061a2ec6bbf0f8cb38e1f06af3a3cfab9f [file] [log] [blame]
rossberg@chromium.org994edf62012-02-06 10:12:55 +00001// Copyright 2012 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
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000032#include "transitions.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000033
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
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
45class Descriptor BASE_EMBEDDED {
46 public:
47 static int IndexFromValue(Object* value) {
48 return Smi::cast(value)->value();
49 }
50
lrn@chromium.org303ada72010-10-27 09:33:13 +000051 MUST_USE_RESULT MaybeObject* KeyToSymbol() {
ager@chromium.org870a0b62008-11-04 11:43:05 +000052 if (!StringShape(key_).IsSymbol()) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000053 MaybeObject* maybe_result = HEAP->LookupSymbol(key_);
54 if (!maybe_result->To(&key_)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055 }
56 return key_;
57 }
58
59 String* GetKey() { return key_; }
60 Object* GetValue() { return value_; }
61 PropertyDetails GetDetails() { return details_; }
62
whesse@chromium.org023421e2010-12-21 12:19:12 +000063#ifdef OBJECT_PRINT
64 void Print(FILE* out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065#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,
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000095 int index)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 : key_(key),
97 value_(value),
98 details_(attributes, type, index) { }
99
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100 friend class DescriptorArray;
101};
102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104class FieldDescriptor: public Descriptor {
105 public:
106 FieldDescriptor(String* key,
107 int field_index,
108 PropertyAttributes attributes,
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000109 int index = 0)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {}
111};
112
113
114class ConstantFunctionDescriptor: public Descriptor {
115 public:
116 ConstantFunctionDescriptor(String* key,
117 JSFunction* function,
118 PropertyAttributes attributes,
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000119 int index)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120 : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
121};
122
123
124class CallbacksDescriptor: public Descriptor {
125 public:
126 CallbacksDescriptor(String* key,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000127 Object* foreign,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128 PropertyAttributes attributes,
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000129 int index = 0)
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000130 : Descriptor(key, foreign, attributes, CALLBACKS, index) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131};
132
133
134class LookupResult BASE_EMBEDDED {
135 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000136 explicit LookupResult(Isolate* isolate)
137 : isolate_(isolate),
138 next_(isolate->top_lookup_result()),
139 lookup_type_(NOT_FOUND),
140 holder_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 cacheable_(true),
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000142 details_(NONE, NONEXISTENT) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000143 isolate->SetTopLookupResult(this);
144 }
145
146 ~LookupResult() {
147 ASSERT(isolate_->top_lookup_result() == this);
148 isolate_->SetTopLookupResult(next_);
149 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150
151 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
152 lookup_type_ = DESCRIPTOR_TYPE;
153 holder_ = holder;
154 details_ = details;
155 number_ = number;
156 }
157
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000158 void TransitionResult(JSObject* holder, int number) {
159 lookup_type_ = TRANSITION_TYPE;
160 details_ = PropertyDetails(NONE, TRANSITION);
161 holder_ = holder;
162 number_ = number;
163 }
164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 void ConstantResult(JSObject* holder) {
166 lookup_type_ = CONSTANT_TYPE;
167 holder_ = holder;
168 details_ =
169 PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM |
170 DONT_DELETE),
171 CALLBACKS);
172 number_ = -1;
173 }
174
175 void DictionaryResult(JSObject* holder, int entry) {
176 lookup_type_ = DICTIONARY_TYPE;
177 holder_ = holder;
178 details_ = holder->property_dictionary()->DetailsAt(entry);
179 number_ = entry;
180 }
181
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000182 void HandlerResult(JSProxy* proxy) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000183 lookup_type_ = HANDLER_TYPE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000184 holder_ = proxy;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 details_ = PropertyDetails(NONE, HANDLER);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000186 cacheable_ = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000187 }
188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 void InterceptorResult(JSObject* holder) {
190 lookup_type_ = INTERCEPTOR_TYPE;
191 holder_ = holder;
192 details_ = PropertyDetails(NONE, INTERCEPTOR);
193 }
194
195 void NotFound() {
196 lookup_type_ = NOT_FOUND;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000197 details_ = PropertyDetails(NONE, NONEXISTENT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000198 holder_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 }
200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201 JSObject* holder() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000202 ASSERT(IsFound());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000203 return JSObject::cast(holder_);
204 }
205
206 JSProxy* proxy() {
207 ASSERT(IsFound());
208 return JSProxy::cast(holder_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209 }
210
211 PropertyType type() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000212 ASSERT(IsFound());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000213 return details_.type();
214 }
215
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 PropertyAttributes GetAttributes() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000217 ASSERT(!IsTransition());
ager@chromium.org5c838252010-02-19 08:53:10 +0000218 ASSERT(IsFound());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000219 ASSERT(details_.type() != NONEXISTENT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 return details_.attributes();
221 }
222
223 PropertyDetails GetPropertyDetails() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000224 ASSERT(!IsTransition());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225 return details_;
226 }
227
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000228 bool IsFastPropertyType() {
229 ASSERT(IsFound());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000230 return IsTransition() || type() != NORMAL;
231 }
232
233 // Property callbacks does not include transitions to callbacks.
234 bool IsPropertyCallbacks() {
235 ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
236 return details_.type() == CALLBACKS;
237 }
238
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000239 bool IsReadOnly() {
240 ASSERT(IsFound());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000241 ASSERT(!IsTransition());
242 ASSERT(details_.type() != NONEXISTENT);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000243 return details_.IsReadOnly();
244 }
245
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000246 bool IsField() {
247 ASSERT(!(details_.type() == FIELD && !IsFound()));
248 return details_.type() == FIELD;
249 }
250
251 bool IsNormal() {
252 ASSERT(!(details_.type() == NORMAL && !IsFound()));
253 return details_.type() == NORMAL;
254 }
255
256 bool IsConstantFunction() {
257 ASSERT(!(details_.type() == CONSTANT_FUNCTION && !IsFound()));
258 return details_.type() == CONSTANT_FUNCTION;
259 }
260
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261 bool IsDontDelete() { return details_.IsDontDelete(); }
262 bool IsDontEnum() { return details_.IsDontEnum(); }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000263 bool IsDeleted() { return details_.IsDeleted(); }
ager@chromium.org5c838252010-02-19 08:53:10 +0000264 bool IsFound() { return lookup_type_ != NOT_FOUND; }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000265 bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000266 bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000267 bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000269 // Is the result is a property excluding transitions and the null descriptor?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000270 bool IsProperty() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000271 return IsFound() && !IsTransition();
ager@chromium.org5c838252010-02-19 08:53:10 +0000272 }
273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000274 bool IsCacheable() { return cacheable_; }
275 void DisallowCaching() { cacheable_ = false; }
276
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000277 Object* GetLazyValue() {
278 switch (type()) {
279 case FIELD:
280 return holder()->FastPropertyAt(GetFieldIndex());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000281 case NORMAL: {
282 Object* value;
283 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
284 if (holder()->IsGlobalObject()) {
285 value = JSGlobalPropertyCell::cast(value)->value();
286 }
287 return value;
288 }
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000289 case CONSTANT_FUNCTION:
290 return GetConstantFunction();
291 default:
292 return Smi::FromInt(0);
293 }
294 }
295
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000296 Map* GetTransitionTarget() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000297 ASSERT(IsTransition());
298 TransitionArray* transitions = holder()->map()->transitions();
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000299 return transitions->GetTarget(number_);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000300 }
301
302 PropertyDetails GetTransitionDetails(Map* map) {
303 ASSERT(IsTransition());
304 TransitionArray* transitions = map->transitions();
305 return transitions->GetTargetDetails(number_);
306 }
307
308 PropertyDetails GetTransitionDetails() {
309 return GetTransitionDetails(holder()->map());
310 }
311
312 bool IsTransitionToField(Map* map) {
313 return IsTransition() && GetTransitionDetails(map).type() == FIELD;
314 }
315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 Map* GetTransitionMap() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000317 ASSERT(IsTransition());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 return Map::cast(GetValue());
319 }
320
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000321 Map* GetTransitionMapFromMap(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000322 ASSERT(IsTransition());
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000323 return map->transitions()->GetTarget(number_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000324 }
325
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000326 int GetTransitionIndex() {
327 ASSERT(IsTransition());
328 return number_;
329 }
330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 int GetFieldIndex() {
332 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000333 ASSERT(IsField());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 return Descriptor::IndexFromValue(GetValue());
335 }
336
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000337 int GetLocalFieldIndexFromMap(Map* map) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000338 ASSERT(IsField());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000339 return Descriptor::IndexFromValue(GetValueFromMap(map)) -
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000340 map->inobject_properties();
341 }
342
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 int GetDictionaryEntry() {
344 ASSERT(lookup_type_ == DICTIONARY_TYPE);
345 return number_;
346 }
347
348 JSFunction* GetConstantFunction() {
349 ASSERT(type() == CONSTANT_FUNCTION);
350 return JSFunction::cast(GetValue());
351 }
352
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000353 JSFunction* GetConstantFunctionFromMap(Map* map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000354 ASSERT(type() == CONSTANT_FUNCTION);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000355 return JSFunction::cast(GetValueFromMap(map));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000356 }
357
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 Object* GetCallbackObject() {
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000359 if (lookup_type_ == CONSTANT_TYPE) {
360 return HEAP->prototype_accessors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000362 ASSERT(!IsTransition());
363 return GetValue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 }
365
whesse@chromium.org023421e2010-12-21 12:19:12 +0000366#ifdef OBJECT_PRINT
367 void Print(FILE* out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368#endif
369
370 Object* GetValue() {
371 if (lookup_type_ == DESCRIPTOR_TYPE) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000372 return GetValueFromMap(holder()->map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373 }
374 // In the dictionary case, the data is held in the value field.
375 ASSERT(lookup_type_ == DICTIONARY_TYPE);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000376 return holder()->GetNormalizedProperty(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377 }
378
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000379 Object* GetValueFromMap(Map* map) const {
380 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
381 return map->instance_descriptors()->GetValue(number_);
382 }
383
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000384 void Iterate(ObjectVisitor* visitor);
385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000387 Isolate* isolate_;
388 LookupResult* next_;
389
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000390 // Where did we find the result;
391 enum {
392 NOT_FOUND,
393 DESCRIPTOR_TYPE,
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000394 TRANSITION_TYPE,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000395 DICTIONARY_TYPE,
396 HANDLER_TYPE,
397 INTERCEPTOR_TYPE,
398 CONSTANT_TYPE
399 } lookup_type_;
400
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000401 JSReceiver* holder_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 int number_;
403 bool cacheable_;
404 PropertyDetails details_;
405};
406
407
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408} } // namespace v8::internal
409
410#endif // V8_PROPERTY_H_