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
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.
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.
28 #ifndef V8_PROPERTY_H_
29 #define V8_PROPERTY_H_
31 #include "allocation.h"
32 #include "transitions.h"
38 // Abstraction for elements in instance-descriptor arrays.
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.
45 class Descriptor BASE_EMBEDDED {
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;
56 Name* GetKey() { return key_; }
57 Object* GetValue() { return value_; }
58 PropertyDetails GetDetails() { return details_; }
61 void Print(FILE* out);
64 void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
69 PropertyDetails details_;
72 Descriptor() : details_(Smi::FromInt(0)) {}
74 void Init(Name* key, Object* value, PropertyDetails details) {
80 Descriptor(Name* key, Object* value, PropertyDetails details)
87 PropertyAttributes attributes,
89 Representation representation,
93 details_(attributes, type, representation, field_index) { }
95 friend class DescriptorArray;
99 class FieldDescriptor: public Descriptor {
101 FieldDescriptor(Name* key,
103 PropertyAttributes attributes,
104 Representation representation)
105 : Descriptor(key, Smi::FromInt(0), attributes,
106 FIELD, representation, field_index) {}
110 class ConstantDescriptor: public Descriptor {
112 ConstantDescriptor(Name* key,
114 PropertyAttributes attributes)
115 : Descriptor(key, value, attributes, CONSTANT,
116 value->OptimalRepresentation()) {}
120 class CallbacksDescriptor: public Descriptor {
122 CallbacksDescriptor(Name* key,
124 PropertyAttributes attributes)
125 : Descriptor(key, foreign, attributes, CALLBACKS,
126 Representation::Tagged()) {}
130 // Holds a property index value distinguishing if it is a field index or an
131 // index inside the object header.
132 class PropertyIndex {
134 static PropertyIndex NewFieldIndex(int index) {
135 return PropertyIndex(index, false);
137 static PropertyIndex NewHeaderIndex(int index) {
138 return PropertyIndex(index, true);
141 bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; }
142 bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; }
145 ASSERT(is_field_index());
149 ASSERT(is_header_index());
153 bool is_inobject(Handle<JSObject> holder) {
154 if (is_header_index()) return true;
155 return field_index() < holder->map()->inobject_properties();
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;
166 static const int kHeaderIndexBit = 1 << 31;
167 static const int kIndexMask = ~kHeaderIndexBit;
169 int value() { return index_ & kIndexMask; }
171 PropertyIndex(int index, bool is_header_based)
172 : index_(index | (is_header_based ? kHeaderIndexBit : 0)) {
173 ASSERT(index <= kIndexMask);
180 class LookupResult BASE_EMBEDDED {
182 explicit LookupResult(Isolate* isolate)
184 next_(isolate->top_lookup_result()),
185 lookup_type_(NOT_FOUND),
189 details_(NONE, NONEXISTENT, Representation::None()) {
190 isolate->SetTopLookupResult(this);
194 ASSERT(isolate()->top_lookup_result() == this);
195 isolate()->SetTopLookupResult(next_);
198 Isolate* isolate() const { return isolate_; }
200 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
201 lookup_type_ = DESCRIPTOR_TYPE;
208 bool CanHoldValue(Handle<Object> value) {
209 if (IsNormal()) return true;
210 ASSERT(!IsTransition());
211 return value->FitsRepresentation(details_.representation());
214 void TransitionResult(JSObject* holder, Map* target) {
215 lookup_type_ = TRANSITION_TYPE;
216 details_ = PropertyDetails(NONE, TRANSITION, Representation::None());
218 transition_ = target;
222 void DictionaryResult(JSObject* holder, int entry) {
223 lookup_type_ = DICTIONARY_TYPE;
226 details_ = holder->property_dictionary()->DetailsAt(entry);
230 void HandlerResult(JSProxy* proxy) {
231 lookup_type_ = HANDLER_TYPE;
234 details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
238 void InterceptorResult(JSObject* holder) {
239 lookup_type_ = INTERCEPTOR_TYPE;
242 details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
246 lookup_type_ = NOT_FOUND;
247 details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
253 return JSObject::cast(holder_);
258 return JSProxy::cast(holder_);
261 PropertyType type() {
263 return details_.type();
266 Representation representation() {
268 ASSERT(!IsTransition());
269 ASSERT(details_.type() != NONEXISTENT);
270 return details_.representation();
273 PropertyAttributes GetAttributes() {
274 ASSERT(!IsTransition());
276 ASSERT(details_.type() != NONEXISTENT);
277 return details_.attributes();
280 PropertyDetails GetPropertyDetails() {
281 ASSERT(!IsTransition());
285 bool IsFastPropertyType() {
287 return IsTransition() || type() != NORMAL;
290 // Property callbacks does not include transitions to callbacks.
291 bool IsPropertyCallbacks() {
292 ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
293 return details_.type() == CALLBACKS;
298 ASSERT(!IsTransition());
299 ASSERT(details_.type() != NONEXISTENT);
300 return details_.IsReadOnly();
304 ASSERT(!(details_.type() == FIELD && !IsFound()));
305 return details_.type() == FIELD;
309 ASSERT(!(details_.type() == NORMAL && !IsFound()));
310 return details_.type() == NORMAL;
314 ASSERT(!(details_.type() == CONSTANT && !IsFound()));
315 return details_.type() == CONSTANT;
318 bool IsConstantFunction() {
319 return IsConstant() && GetValue()->IsJSFunction();
322 bool IsDontDelete() { return details_.IsDontDelete(); }
323 bool IsDontEnum() { return details_.IsDontEnum(); }
324 bool IsFound() { return lookup_type_ != NOT_FOUND; }
325 bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; }
326 bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
327 bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; }
329 // Is the result is a property excluding transitions and the null descriptor?
331 return IsFound() && !IsTransition();
334 bool IsDataProperty() {
341 Object* callback = GetCallbackObject();
342 return callback->IsAccessorInfo() || callback->IsForeign();
354 bool IsCacheable() { return cacheable_; }
355 void DisallowCaching() { cacheable_ = false; }
357 Object* GetLazyValue() {
360 return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
363 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
364 if (holder()->IsGlobalObject()) {
365 value = PropertyCell::cast(value)->value();
370 return GetConstant();
376 return isolate()->heap()->the_hole_value();
382 Map* GetTransitionTarget() {
386 PropertyDetails GetTransitionDetails() {
387 return transition_->GetLastDescriptorDetails();
390 bool IsTransitionToField() {
391 return IsTransition() && GetTransitionDetails().type() == FIELD;
394 bool IsTransitionToConstant() {
395 return IsTransition() && GetTransitionDetails().type() == CONSTANT;
398 int GetTransitionIndex() {
399 ASSERT(IsTransition());
403 int GetDescriptorIndex() {
404 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
408 PropertyIndex GetFieldIndex() {
409 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
410 return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
413 int GetLocalFieldIndexFromMap(Map* map) {
414 return GetFieldIndexFromMap(map) - map->inobject_properties();
417 int GetDictionaryEntry() {
418 ASSERT(lookup_type_ == DICTIONARY_TYPE);
422 JSFunction* GetConstantFunction() {
423 ASSERT(type() == CONSTANT);
424 return JSFunction::cast(GetValue());
427 Object* GetConstantFromMap(Map* map) {
428 ASSERT(type() == CONSTANT);
429 return GetValueFromMap(map);
432 JSFunction* GetConstantFunctionFromMap(Map* map) {
433 return JSFunction::cast(GetConstantFromMap(map));
436 Object* GetConstant() {
437 ASSERT(type() == CONSTANT);
441 Object* GetCallbackObject() {
442 ASSERT(type() == CALLBACKS && !IsTransition());
447 void Print(FILE* out);
451 if (lookup_type_ == DESCRIPTOR_TYPE) {
452 return GetValueFromMap(holder()->map());
454 // In the dictionary case, the data is held in the value field.
455 ASSERT(lookup_type_ == DICTIONARY_TYPE);
456 return holder()->GetNormalizedProperty(this);
459 Object* GetValueFromMap(Map* map) const {
460 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
461 ASSERT(number_ < map->NumberOfOwnDescriptors());
462 return map->instance_descriptors()->GetValue(number_);
465 int GetFieldIndexFromMap(Map* map) const {
466 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
467 ASSERT(number_ < map->NumberOfOwnDescriptors());
468 return map->instance_descriptors()->GetFieldIndex(number_);
471 void Iterate(ObjectVisitor* visitor);
477 // Where did we find the result;
491 PropertyDetails details_;
495 } } // namespace v8::internal
497 #endif // V8_PROPERTY_H_