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),
188 details_(NONE, NONEXISTENT, Representation::None()) {
189 isolate->SetTopLookupResult(this);
193 ASSERT(isolate()->top_lookup_result() == this);
194 isolate()->SetTopLookupResult(next_);
197 Isolate* isolate() const { return isolate_; }
199 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
200 lookup_type_ = DESCRIPTOR_TYPE;
206 bool CanHoldValue(Handle<Object> value) {
207 if (IsNormal()) return true;
208 ASSERT(!IsTransition());
209 return value->FitsRepresentation(details_.representation());
212 void TransitionResult(JSObject* holder, int number) {
213 lookup_type_ = TRANSITION_TYPE;
214 details_ = PropertyDetails(NONE, TRANSITION, Representation::None());
219 void DictionaryResult(JSObject* holder, int entry) {
220 lookup_type_ = DICTIONARY_TYPE;
222 details_ = holder->property_dictionary()->DetailsAt(entry);
226 void HandlerResult(JSProxy* proxy) {
227 lookup_type_ = HANDLER_TYPE;
229 details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
233 void InterceptorResult(JSObject* holder) {
234 lookup_type_ = INTERCEPTOR_TYPE;
236 details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
240 lookup_type_ = NOT_FOUND;
241 details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
247 return JSObject::cast(holder_);
252 return JSProxy::cast(holder_);
255 PropertyType type() {
257 return details_.type();
260 Representation representation() {
262 ASSERT(!IsTransition());
263 ASSERT(details_.type() != NONEXISTENT);
264 return details_.representation();
267 PropertyAttributes GetAttributes() {
268 ASSERT(!IsTransition());
270 ASSERT(details_.type() != NONEXISTENT);
271 return details_.attributes();
274 PropertyDetails GetPropertyDetails() {
275 ASSERT(!IsTransition());
279 bool IsFastPropertyType() {
281 return IsTransition() || type() != NORMAL;
284 // Property callbacks does not include transitions to callbacks.
285 bool IsPropertyCallbacks() {
286 ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
287 return details_.type() == CALLBACKS;
292 ASSERT(!IsTransition());
293 ASSERT(details_.type() != NONEXISTENT);
294 return details_.IsReadOnly();
298 ASSERT(!(details_.type() == FIELD && !IsFound()));
299 return details_.type() == FIELD;
303 ASSERT(!(details_.type() == NORMAL && !IsFound()));
304 return details_.type() == NORMAL;
308 ASSERT(!(details_.type() == CONSTANT && !IsFound()));
309 return details_.type() == CONSTANT;
312 bool IsConstantFunction() {
313 return IsConstant() && GetValue()->IsJSFunction();
316 bool IsDontDelete() { return details_.IsDontDelete(); }
317 bool IsDontEnum() { return details_.IsDontEnum(); }
318 bool IsFound() { return lookup_type_ != NOT_FOUND; }
319 bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; }
320 bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
321 bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; }
323 // Is the result is a property excluding transitions and the null descriptor?
325 return IsFound() && !IsTransition();
328 bool IsDataProperty() {
335 Object* callback = GetCallbackObject();
336 return callback->IsAccessorInfo() || callback->IsForeign();
348 bool IsCacheable() { return cacheable_; }
349 void DisallowCaching() { cacheable_ = false; }
351 Object* GetLazyValue() {
354 return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
357 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
358 if (holder()->IsGlobalObject()) {
359 value = PropertyCell::cast(value)->value();
364 return GetConstant();
370 return isolate()->heap()->the_hole_value();
376 Map* GetTransitionTarget(Map* map) {
377 ASSERT(IsTransition());
378 TransitionArray* transitions = map->transitions();
379 return transitions->GetTarget(number_);
382 Map* GetTransitionTarget() {
383 return GetTransitionTarget(holder()->map());
386 PropertyDetails GetTransitionDetails(Map* map) {
387 ASSERT(IsTransition());
388 TransitionArray* transitions = map->transitions();
389 return transitions->GetTargetDetails(number_);
392 PropertyDetails GetTransitionDetails() {
393 return GetTransitionDetails(holder()->map());
396 bool IsTransitionToField(Map* map) {
397 return IsTransition() && GetTransitionDetails(map).type() == FIELD;
400 bool IsTransitionToConstant(Map* map) {
401 return IsTransition() && GetTransitionDetails(map).type() == CONSTANT;
404 Map* GetTransitionMap() {
405 ASSERT(IsTransition());
406 return Map::cast(GetValue());
409 Map* GetTransitionMapFromMap(Map* map) {
410 ASSERT(IsTransition());
411 return map->transitions()->GetTarget(number_);
414 int GetTransitionIndex() {
415 ASSERT(IsTransition());
419 int GetDescriptorIndex() {
420 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
424 PropertyIndex GetFieldIndex() {
425 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
426 return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
429 int GetLocalFieldIndexFromMap(Map* map) {
430 return GetFieldIndexFromMap(map) - map->inobject_properties();
433 int GetDictionaryEntry() {
434 ASSERT(lookup_type_ == DICTIONARY_TYPE);
438 JSFunction* GetConstantFunction() {
439 ASSERT(type() == CONSTANT);
440 return JSFunction::cast(GetValue());
443 Object* GetConstantFromMap(Map* map) {
444 ASSERT(type() == CONSTANT);
445 return GetValueFromMap(map);
448 JSFunction* GetConstantFunctionFromMap(Map* map) {
449 return JSFunction::cast(GetConstantFromMap(map));
452 Object* GetConstant() {
453 ASSERT(type() == CONSTANT);
457 Object* GetCallbackObject() {
458 ASSERT(type() == CALLBACKS && !IsTransition());
463 void Print(FILE* out);
467 if (lookup_type_ == DESCRIPTOR_TYPE) {
468 return GetValueFromMap(holder()->map());
470 // In the dictionary case, the data is held in the value field.
471 ASSERT(lookup_type_ == DICTIONARY_TYPE);
472 return holder()->GetNormalizedProperty(this);
475 Object* GetValueFromMap(Map* map) const {
476 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
477 ASSERT(number_ < map->NumberOfOwnDescriptors());
478 return map->instance_descriptors()->GetValue(number_);
481 int GetFieldIndexFromMap(Map* map) const {
482 ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
483 ASSERT(number_ < map->NumberOfOwnDescriptors());
484 return map->instance_descriptors()->GetFieldIndex(number_);
487 void Iterate(ObjectVisitor* visitor);
493 // Where did we find the result;
506 PropertyDetails details_;
510 } } // namespace v8::internal
512 #endif // V8_PROPERTY_H_