| Index: src/property.h
|
| diff --git a/src/property.h b/src/property.h
|
| index 76ae0fbae1278e8ec420d28c27450430da4e87d6..53c344191ae66ce5d38615ab6c75660c93d21450 100644
|
| --- a/src/property.h
|
| +++ b/src/property.h
|
| @@ -29,6 +29,7 @@
|
| #define V8_PROPERTY_H_
|
|
|
| #include "allocation.h"
|
| +#include "transitions.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
| @@ -68,8 +69,6 @@ class Descriptor BASE_EMBEDDED {
|
| details_ = PropertyDetails(details_.attributes(), details_.type(), index);
|
| }
|
|
|
| - bool ContainsTransition();
|
| -
|
| private:
|
| String* key_;
|
| Object* value_;
|
| @@ -101,27 +100,6 @@ class Descriptor BASE_EMBEDDED {
|
| friend class DescriptorArray;
|
| };
|
|
|
| -// A pointer from a map to the new map that is created by adding
|
| -// a named property. These are key to the speed and functioning of V8.
|
| -// The two maps should always have the same prototype, since
|
| -// MapSpace::CreateBackPointers depends on this.
|
| -class MapTransitionDescriptor: public Descriptor {
|
| - public:
|
| - MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
|
| - : Descriptor(key, map, attributes, MAP_TRANSITION) { }
|
| -};
|
| -
|
| -// Marks a field name in a map so that adding the field is guaranteed
|
| -// to create a FIELD descriptor in the new map. Used after adding
|
| -// a constant function the first time, creating a CONSTANT_FUNCTION
|
| -// descriptor in the new map. This avoids creating multiple maps with
|
| -// the same CONSTANT_FUNCTION field.
|
| -class ConstTransitionDescriptor: public Descriptor {
|
| - public:
|
| - explicit ConstTransitionDescriptor(String* key, Map* map)
|
| - : Descriptor(key, map, NONE, CONSTANT_TRANSITION) { }
|
| -};
|
| -
|
|
|
| class FieldDescriptor: public Descriptor {
|
| public:
|
| @@ -153,36 +131,6 @@ class CallbacksDescriptor: public Descriptor {
|
| };
|
|
|
|
|
| -template <class T>
|
| -bool IsPropertyDescriptor(T* desc) {
|
| - switch (desc->type()) {
|
| - case NORMAL:
|
| - case FIELD:
|
| - case CONSTANT_FUNCTION:
|
| - case HANDLER:
|
| - case INTERCEPTOR:
|
| - return true;
|
| - case CALLBACKS: {
|
| - Object* callback_object = desc->GetCallbackObject();
|
| - // Non-JavaScript (i.e. native) accessors are always a property, otherwise
|
| - // either the getter or the setter must be an accessor. Put another way:
|
| - // If we only see map transitions and holes in a pair, this is not a
|
| - // property.
|
| - return (!callback_object->IsAccessorPair() ||
|
| - AccessorPair::cast(callback_object)->ContainsAccessor());
|
| - }
|
| - case MAP_TRANSITION:
|
| - case CONSTANT_TRANSITION:
|
| - return false;
|
| - case NONEXISTENT:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - UNREACHABLE(); // keep the compiler happy
|
| - return false;
|
| -}
|
| -
|
| -
|
| class LookupResult BASE_EMBEDDED {
|
| public:
|
| explicit LookupResult(Isolate* isolate)
|
| @@ -207,6 +155,13 @@ class LookupResult BASE_EMBEDDED {
|
| number_ = number;
|
| }
|
|
|
| + void TransitionResult(JSObject* holder, int number) {
|
| + lookup_type_ = TRANSITION_TYPE;
|
| + details_ = PropertyDetails(NONE, TRANSITION);
|
| + holder_ = holder;
|
| + number_ = number;
|
| + }
|
| +
|
| void ConstantResult(JSObject* holder) {
|
| lookup_type_ = CONSTANT_TYPE;
|
| holder_ = holder;
|
| @@ -259,27 +214,39 @@ class LookupResult BASE_EMBEDDED {
|
| }
|
|
|
| PropertyAttributes GetAttributes() {
|
| + ASSERT(!IsTransition());
|
| ASSERT(IsFound());
|
| + ASSERT(details_.type() != NONEXISTENT);
|
| return details_.attributes();
|
| }
|
|
|
| PropertyDetails GetPropertyDetails() {
|
| + ASSERT(!IsTransition());
|
| return details_;
|
| }
|
|
|
| bool IsFastPropertyType() {
|
| ASSERT(IsFound());
|
| - return type() != NORMAL;
|
| + return IsTransition() || type() != NORMAL;
|
| }
|
|
|
| - bool IsReadOnly() {
|
| - ASSERT(IsFound());
|
| - return details_.IsReadOnly();
|
| + // Property callbacks does not include transitions to callbacks.
|
| + bool IsPropertyCallbacks() {
|
| + ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
|
| + return details_.type() == CALLBACKS;
|
| }
|
|
|
| + // Is callbacks contains both property callbacks and transitions to callbacks.
|
| bool IsCallbacks() {
|
| - ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
|
| - return details_.type() == CALLBACKS;
|
| + return IsPropertyCallbacks() ||
|
| + (IsTransition() && GetTransitionValue()->IsAccessorPair());
|
| + }
|
| +
|
| + bool IsReadOnly() {
|
| + ASSERT(IsFound());
|
| + ASSERT(!IsTransition());
|
| + ASSERT(details_.type() != NONEXISTENT);
|
| + return details_.IsReadOnly();
|
| }
|
|
|
| bool IsField() {
|
| @@ -297,21 +264,17 @@ class LookupResult BASE_EMBEDDED {
|
| return details_.type() == CONSTANT_FUNCTION;
|
| }
|
|
|
| - bool IsMapTransition() {
|
| - ASSERT(!(details_.type() == MAP_TRANSITION && !IsFound()));
|
| - return details_.type() == MAP_TRANSITION;
|
| - }
|
| -
|
| bool IsDontDelete() { return details_.IsDontDelete(); }
|
| bool IsDontEnum() { return details_.IsDontEnum(); }
|
| bool IsDeleted() { return details_.IsDeleted(); }
|
| bool IsFound() { return lookup_type_ != NOT_FOUND; }
|
| + bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; }
|
| bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
|
| bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; }
|
|
|
| // Is the result is a property excluding transitions and the null descriptor?
|
| bool IsProperty() {
|
| - return IsFound() && IsPropertyDescriptor(this);
|
| + return IsFound() && !IsTransition();
|
| }
|
|
|
| bool IsCacheable() { return cacheable_; }
|
| @@ -336,17 +299,35 @@ class LookupResult BASE_EMBEDDED {
|
| }
|
| }
|
|
|
| + Object* GetTransitionValue() {
|
| + ASSERT(IsTransition());
|
| + TransitionArray* transitions = holder()->map()->transitions();
|
| + Object* value = transitions->GetValue(number_);
|
| + return value;
|
| + }
|
| +
|
| + PropertyDetails GetTransitionDetails(Map* map) {
|
| + ASSERT(IsTransition());
|
| + TransitionArray* transitions = map->transitions();
|
| + return transitions->GetTargetDetails(number_);
|
| + }
|
| +
|
| + PropertyDetails GetTransitionDetails() {
|
| + return GetTransitionDetails(holder()->map());
|
| + }
|
| +
|
| + bool IsTransitionToField(Map* map) {
|
| + return IsTransition() && GetTransitionDetails(map).type() == FIELD;
|
| + }
|
| +
|
| Map* GetTransitionMap() {
|
| - ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
|
| - ASSERT(type() == MAP_TRANSITION ||
|
| - type() == CONSTANT_TRANSITION);
|
| + ASSERT(IsTransition());
|
| return Map::cast(GetValue());
|
| }
|
|
|
| Map* GetTransitionMapFromMap(Map* map) {
|
| - ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
|
| - ASSERT(type() == MAP_TRANSITION);
|
| - return Map::cast(map->instance_descriptors()->GetValue(number_));
|
| + ASSERT(IsTransition());
|
| + return Map::cast(map->transitions()->GetValue(number_));
|
| }
|
|
|
| int GetFieldIndex() {
|
| @@ -380,11 +361,14 @@ class LookupResult BASE_EMBEDDED {
|
| }
|
|
|
| Object* GetCallbackObject() {
|
| - if (lookup_type_ == CONSTANT_TYPE) {
|
| - // For now we only have the __proto__ as constant type.
|
| - return HEAP->prototype_accessors();
|
| + switch (lookup_type_) {
|
| + case CONSTANT_TYPE:
|
| + return HEAP->prototype_accessors();
|
| + case TRANSITION_TYPE:
|
| + return GetTransitionValue();
|
| + default:
|
| + return GetValue();
|
| }
|
| - return GetValue();
|
| }
|
|
|
| #ifdef OBJECT_PRINT
|
| @@ -411,6 +395,7 @@ class LookupResult BASE_EMBEDDED {
|
| enum {
|
| NOT_FOUND,
|
| DESCRIPTOR_TYPE,
|
| + TRANSITION_TYPE,
|
| DICTIONARY_TYPE,
|
| HANDLER_TYPE,
|
| INTERCEPTOR_TYPE,
|
|
|