From e26ff6c45fa5a1c1a4fc462e1278fdac40ce9c16 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Fri, 4 Apr 2014 04:49:07 +0000 Subject: [PATCH] Get rid of the TRANSITION PropertyType and consistently use CanHoldValue(). R=verwaest@chromium.org Review URL: https://codereview.chromium.org/223193005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20494 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/bootstrapper.cc | 1 - src/heap-snapshot-generator.cc | 1 - src/ic.cc | 165 ++++++++++++++++++++--------------------- src/objects-inl.h | 18 ++--- src/objects-printer.cc | 3 - src/objects.cc | 145 +++++++++++++++++------------------- src/objects.h | 1 + src/property-details.h | 3 +- src/property.cc | 108 ++++++++++++++------------- src/property.h | 129 ++++++++++++++++++-------------- src/runtime.cc | 36 ++++----- 11 files changed, 310 insertions(+), 300 deletions(-) diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 1da742e..9486b41 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -2464,7 +2464,6 @@ void Genesis::TransferNamedProperties(Handle from, // Do not occur since the from object has fast properties. case HANDLER: case INTERCEPTOR: - case TRANSITION: case NONEXISTENT: // No element in instance descriptors have proxy or interceptor type. UNREACHABLE(); diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index 8410ba3..0f3e6ad 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -1671,7 +1671,6 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { case HANDLER: // only in lookup results, not in descriptors case INTERCEPTOR: // only in lookup results, not in descriptors break; - case TRANSITION: case NONEXISTENT: UNREACHABLE(); break; diff --git a/src/ic.cc b/src/ic.cc index 36c7e5a..495c727 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -1167,9 +1167,7 @@ static bool LookupForWrite(Handle receiver, // chain check. This avoids a double lookup, but requires us to pass in the // receiver when trying to fetch extra information from the transition. receiver->map()->LookupTransition(*holder, *name, lookup); - if (!lookup->IsTransition()) return false; - PropertyDetails target_details = lookup->GetTransitionDetails(); - if (target_details.IsReadOnly()) return false; + if (!lookup->IsTransition() || lookup->IsReadOnly()) return false; // If the value that's being stored does not fit in the field that the // instance would transition to, create a new transition that fits the value. @@ -1178,7 +1176,7 @@ static bool LookupForWrite(Handle receiver, // Ensure the instance and its map were migrated before trying to update the // transition target. ASSERT(!receiver->map()->is_deprecated()); - if (!value->FitsRepresentation(target_details.representation())) { + if (!lookup->CanHoldValue(value)) { Handle target(lookup->GetTransitionTarget()); Map::GeneralizeRepresentation( target, target->LastAdded(), @@ -1327,93 +1325,94 @@ Handle StoreIC::CompileHandler(LookupResult* lookup, Handle holder(lookup->holder()); // Handlers do not use strict mode. StoreStubCompiler compiler(isolate(), SLOPPY, kind()); - switch (lookup->type()) { - case FIELD: - return compiler.CompileStoreField(receiver, lookup, name); - case TRANSITION: { - // Explicitly pass in the receiver map since LookupForWrite may have - // stored something else than the receiver in the holder. - Handle transition(lookup->GetTransitionTarget()); - PropertyDetails details = transition->GetLastDescriptorDetails(); - - if (details.type() == CALLBACKS || details.attributes() != NONE) break; + if (lookup->IsTransition()) { + // Explicitly pass in the receiver map since LookupForWrite may have + // stored something else than the receiver in the holder. + Handle transition(lookup->GetTransitionTarget()); + PropertyDetails details = lookup->GetPropertyDetails(); + if (details.type() != CALLBACKS && details.attributes() == NONE) { return compiler.CompileStoreTransition( receiver, lookup, transition, name); } - case NORMAL: - if (kind() == Code::KEYED_STORE_IC) break; - if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) { - // The stub generated for the global object picks the value directly - // from the property cell. So the property must be directly on the - // global object. - Handle global = receiver->IsJSGlobalProxy() - ? handle(GlobalObject::cast(receiver->GetPrototype())) - : Handle::cast(receiver); - Handle cell(global->GetPropertyCell(lookup), isolate()); - Handle union_type = PropertyCell::UpdatedType(cell, value); - StoreGlobalStub stub( - union_type->IsConstant(), receiver->IsJSGlobalProxy()); - Handle code = stub.GetCodeCopyFromTemplate( - isolate(), global, cell); - // TODO(verwaest): Move caching of these NORMAL stubs outside as well. - HeapObject::UpdateMapCodeCache(receiver, name, code); - return code; - } - ASSERT(holder.is_identical_to(receiver)); - return isolate()->builtins()->StoreIC_Normal(); - case CALLBACKS: { - Handle callback(lookup->GetCallbackObject(), isolate()); - if (callback->IsExecutableAccessorInfo()) { - Handle info = - Handle::cast(callback); - if (v8::ToCData
(info->setter()) == 0) break; - if (!holder->HasFastProperties()) break; - if (!info->IsCompatibleReceiver(*receiver)) break; - return compiler.CompileStoreCallback(receiver, holder, name, info); - } else if (callback->IsAccessorPair()) { - Handle setter( - Handle::cast(callback)->setter(), isolate()); - if (!setter->IsJSFunction()) break; - if (holder->IsGlobalObject()) break; - if (!holder->HasFastProperties()) break; - Handle function = Handle::cast(setter); - CallOptimization call_optimization(function); - if (call_optimization.is_simple_api_call() && - call_optimization.IsCompatibleReceiver(receiver, holder)) { - return compiler.CompileStoreCallback( - receiver, holder, name, call_optimization); + } else { + switch (lookup->type()) { + case FIELD: + return compiler.CompileStoreField(receiver, lookup, name); + case NORMAL: + if (kind() == Code::KEYED_STORE_IC) break; + if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) { + // The stub generated for the global object picks the value directly + // from the property cell. So the property must be directly on the + // global object. + Handle global = receiver->IsJSGlobalProxy() + ? handle(GlobalObject::cast(receiver->GetPrototype())) + : Handle::cast(receiver); + Handle cell(global->GetPropertyCell(lookup), isolate()); + Handle union_type = PropertyCell::UpdatedType(cell, value); + StoreGlobalStub stub( + union_type->IsConstant(), receiver->IsJSGlobalProxy()); + Handle code = stub.GetCodeCopyFromTemplate( + isolate(), global, cell); + // TODO(verwaest): Move caching of these NORMAL stubs outside as well. + HeapObject::UpdateMapCodeCache(receiver, name, code); + return code; + } + ASSERT(holder.is_identical_to(receiver)); + return isolate()->builtins()->StoreIC_Normal(); + case CALLBACKS: { + Handle callback(lookup->GetCallbackObject(), isolate()); + if (callback->IsExecutableAccessorInfo()) { + Handle info = + Handle::cast(callback); + if (v8::ToCData
(info->setter()) == 0) break; + if (!holder->HasFastProperties()) break; + if (!info->IsCompatibleReceiver(*receiver)) break; + return compiler.CompileStoreCallback(receiver, holder, name, info); + } else if (callback->IsAccessorPair()) { + Handle setter( + Handle::cast(callback)->setter(), isolate()); + if (!setter->IsJSFunction()) break; + if (holder->IsGlobalObject()) break; + if (!holder->HasFastProperties()) break; + Handle function = Handle::cast(setter); + CallOptimization call_optimization(function); + if (call_optimization.is_simple_api_call() && + call_optimization.IsCompatibleReceiver(receiver, holder)) { + return compiler.CompileStoreCallback( + receiver, holder, name, call_optimization); + } + return compiler.CompileStoreViaSetter( + receiver, holder, name, Handle::cast(setter)); + } + // TODO(dcarney): Handle correctly. + if (callback->IsDeclaredAccessorInfo()) break; + ASSERT(callback->IsForeign()); + + // Use specialized code for setting the length of arrays with fast + // properties. Slow properties might indicate redefinition of the length + // property. + if (receiver->IsJSArray() && + name->Equals(isolate()->heap()->length_string()) && + Handle::cast(receiver)->AllowsSetElementsLength() && + receiver->HasFastProperties()) { + return compiler.CompileStoreArrayLength(receiver, lookup, name); } - return compiler.CompileStoreViaSetter( - receiver, holder, name, Handle::cast(setter)); - } - // TODO(dcarney): Handle correctly. - if (callback->IsDeclaredAccessorInfo()) break; - ASSERT(callback->IsForeign()); - // Use specialized code for setting the length of arrays with fast - // properties. Slow properties might indicate redefinition of the length - // property. - if (receiver->IsJSArray() && - name->Equals(isolate()->heap()->length_string()) && - Handle::cast(receiver)->AllowsSetElementsLength() && - receiver->HasFastProperties()) { - return compiler.CompileStoreArrayLength(receiver, lookup, name); + // No IC support for old-style native accessors. + break; } - - // No IC support for old-style native accessors. - break; + case INTERCEPTOR: + if (kind() == Code::KEYED_STORE_IC) break; + ASSERT(HasInterceptorSetter(*holder)); + return compiler.CompileStoreInterceptor(receiver, name); + case CONSTANT: + break; + case NONEXISTENT: + case HANDLER: + UNREACHABLE(); + break; } - case INTERCEPTOR: - if (kind() == Code::KEYED_STORE_IC) break; - ASSERT(HasInterceptorSetter(*holder)); - return compiler.CompileStoreInterceptor(receiver, name); - case CONSTANT: - break; - case NONEXISTENT: - case HANDLER: - UNREACHABLE(); - break; } return slow_stub(); } diff --git a/src/objects-inl.h b/src/objects-inl.h index 41fe7b1..43d2354 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2629,15 +2629,9 @@ void Map::LookupDescriptor(JSObject* holder, void Map::LookupTransition(JSObject* holder, Name* name, LookupResult* result) { - if (HasTransitionArray()) { - TransitionArray* transition_array = transitions(); - int number = transition_array->Search(name); - if (number != TransitionArray::kNotFound) { - return result->TransitionResult( - holder, transition_array->GetTarget(number)); - } - } - result->NotFound(); + int transition_index = this->SearchTransition(name); + if (transition_index == TransitionArray::kNotFound) return result->NotFound(); + result->TransitionResult(holder, this->GetTransition(transition_index)); } @@ -4904,6 +4898,12 @@ Map* Map::GetTransition(int transition_index) { } +int Map::SearchTransition(Name* name) { + if (HasTransitionArray()) return transitions()->Search(name); + return TransitionArray::kNotFound; +} + + MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) { TransitionArray* transitions; MaybeObject* maybe_transitions = AddTransition( diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 518167c..a59b1e9 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -271,7 +271,6 @@ void JSObject::PrintProperties(FILE* out) { case HANDLER: // only in lookup results, not in descriptors case INTERCEPTOR: // only in lookup results, not in descriptors // There are no transitions in the descriptor array. - case TRANSITION: case NONEXISTENT: UNREACHABLE(); break; @@ -428,7 +427,6 @@ void JSObject::PrintTransitions(FILE* out) { case NORMAL: case HANDLER: case INTERCEPTOR: - case TRANSITION: case NONEXISTENT: UNREACHABLE(); break; @@ -1223,7 +1221,6 @@ void TransitionArray::PrintTransitions(FILE* out) { case NORMAL: case HANDLER: case INTERCEPTOR: - case TRANSITION: case NONEXISTENT: UNREACHABLE(); break; diff --git a/src/objects.cc b/src/objects.cc index a544c86..373fe97 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -670,7 +670,6 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck( } case HANDLER: - case TRANSITION: case NONEXISTENT: UNREACHABLE(); } @@ -944,7 +943,6 @@ MaybeObject* Object::GetProperty(Object* receiver, RETURN_IF_EMPTY_HANDLE(isolate, value); return *value; } - case TRANSITION: case NONEXISTENT: UNREACHABLE(); break; @@ -3077,7 +3075,6 @@ Handle JSObject::SetPropertyViaPrototypes(Handle object, return JSProxy::SetPropertyViaPrototypesWithHandler( proxy, object, name, value, attributes, strict_mode, done); } - case TRANSITION: case NONEXISTENT: UNREACHABLE(); break; @@ -3915,7 +3912,7 @@ Handle JSObject::SetPropertyUsingTransition( // Keep the target CONSTANT if the same value is stored. // TODO(verwaest): Also support keeping the placeholder // (value->IsUninitialized) as constant. - if (!value->FitsRepresentation(details.representation()) || + if (!lookup->CanHoldValue(value) || (details.type() == CONSTANT && descriptors->GetValue(descriptor) != *value)) { transition_map = Map::GeneralizeRepresentation(transition_map, @@ -3948,7 +3945,7 @@ static void SetPropertyToField(LookupResult* lookup, Handle name, Handle value) { Representation representation = lookup->representation(); - if (!value->FitsRepresentation(representation) || + if (!lookup->CanHoldValue(value) || lookup->type() == CONSTANT) { JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()), lookup->GetDescriptorIndex(), @@ -4091,34 +4088,35 @@ Handle JSObject::SetPropertyForResult(Handle object, // This is a real property that is not read-only, or it is a // transition or null descriptor and there are no setters in the prototypes. Handle result = value; - switch (lookup->type()) { - case NORMAL: - SetNormalizedProperty(handle(lookup->holder()), lookup, value); - break; - case FIELD: - SetPropertyToField(lookup, name, value); - break; - case CONSTANT: - // Only replace the constant if necessary. - if (*value == lookup->GetConstant()) return value; - SetPropertyToField(lookup, name, value); - break; - case CALLBACKS: { - Handle callback_object(lookup->GetCallbackObject(), isolate); - return SetPropertyWithCallback(object, callback_object, name, value, - handle(lookup->holder()), strict_mode); + if (lookup->IsTransition()) { + result = SetPropertyUsingTransition(handle(lookup->holder()), lookup, + name, value, attributes); + } else { + switch (lookup->type()) { + case NORMAL: + SetNormalizedProperty(handle(lookup->holder()), lookup, value); + break; + case FIELD: + SetPropertyToField(lookup, name, value); + break; + case CONSTANT: + // Only replace the constant if necessary. + if (*value == lookup->GetConstant()) return value; + SetPropertyToField(lookup, name, value); + break; + case CALLBACKS: { + Handle callback_object(lookup->GetCallbackObject(), isolate); + return SetPropertyWithCallback(object, callback_object, name, value, + handle(lookup->holder()), strict_mode); + } + case INTERCEPTOR: + result = SetPropertyWithInterceptor( + handle(lookup->holder()), name, value, attributes, strict_mode); + break; + case HANDLER: + case NONEXISTENT: + UNREACHABLE(); } - case INTERCEPTOR: - result = SetPropertyWithInterceptor(handle(lookup->holder()), name, value, - attributes, strict_mode); - break; - case TRANSITION: - result = SetPropertyUsingTransition(handle(lookup->holder()), lookup, - name, value, attributes); - break; - case HANDLER: - case NONEXISTENT: - UNREACHABLE(); } RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle()); @@ -4216,33 +4214,33 @@ Handle JSObject::SetLocalPropertyIgnoreAttributes( } // Check of IsReadOnly removed from here in clone. - switch (lookup.type()) { - case NORMAL: - ReplaceSlowProperty(object, name, value, attributes); - break; - case FIELD: - SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); - break; - case CONSTANT: - // Only replace the constant if necessary. - if (lookup.GetAttributes() != attributes || - *value != lookup.GetConstant()) { + if (lookup.IsTransition()) { + Handle result = SetPropertyUsingTransition( + handle(lookup.holder()), &lookup, name, value, attributes); + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle()); + } else { + switch (lookup.type()) { + case NORMAL: + ReplaceSlowProperty(object, name, value, attributes); + break; + case FIELD: SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); - } - break; - case CALLBACKS: - ConvertAndSetLocalProperty(&lookup, name, value, attributes); - break; - case TRANSITION: { - Handle result = SetPropertyUsingTransition( - handle(lookup.holder()), &lookup, name, value, attributes); - RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle()); - break; + break; + case CONSTANT: + // Only replace the constant if necessary. + if (lookup.GetAttributes() != attributes || + *value != lookup.GetConstant()) { + SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); + } + break; + case CALLBACKS: + ConvertAndSetLocalProperty(&lookup, name, value, attributes); + break; + case NONEXISTENT: + case HANDLER: + case INTERCEPTOR: + UNREACHABLE(); } - case NONEXISTENT: - case HANDLER: - case INTERCEPTOR: - UNREACHABLE(); } if (is_observed) { @@ -4386,7 +4384,6 @@ PropertyAttributes JSReceiver::GetPropertyAttributeForResult( Handle::cast(receiver), name, continue_search); - case TRANSITION: case NONEXISTENT: UNREACHABLE(); } @@ -4629,7 +4626,6 @@ void JSObject::NormalizeProperties(Handle object, break; case HANDLER: case NORMAL: - case TRANSITION: case NONEXISTENT: UNREACHABLE(); break; @@ -5579,11 +5575,11 @@ MaybeHandle JSObject::Freeze(Handle object) { } } - LookupResult result(isolate); - Handle old_map(object->map()); - old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result); - if (result.IsTransition()) { - Handle transition_map(result.GetTransitionTarget()); + Handle old_map(object->map(), isolate); + int transition_index = old_map->SearchTransition( + isolate->heap()->frozen_symbol()); + if (transition_index != TransitionArray::kNotFound) { + Handle transition_map(old_map->GetTransition(transition_index)); ASSERT(transition_map->has_dictionary_elements()); ASSERT(transition_map->is_frozen()); ASSERT(!transition_map->is_extensible()); @@ -5635,22 +5631,19 @@ MaybeHandle JSObject::Freeze(Handle object) { void JSObject::SetObserved(Handle object) { - ASSERT(!object->map()->is_observed()); Isolate* isolate = object->GetIsolate(); - - LookupResult result(isolate); - object->map()->LookupTransition(*object, - isolate->heap()->observed_symbol(), - &result); - Handle new_map; - if (result.IsTransition()) { - new_map = handle(result.GetTransitionTarget()); + Handle old_map(object->map(), isolate); + ASSERT(!old_map->is_observed()); + int transition_index = old_map->SearchTransition( + isolate->heap()->observed_symbol()); + if (transition_index != TransitionArray::kNotFound) { + new_map = handle(old_map->GetTransition(transition_index), isolate); ASSERT(new_map->is_observed()); - } else if (object->map()->CanHaveMoreTransitions()) { - new_map = Map::CopyForObserved(handle(object->map())); + } else if (old_map->CanHaveMoreTransitions()) { + new_map = Map::CopyForObserved(old_map); } else { - new_map = Map::Copy(handle(object->map())); + new_map = Map::Copy(old_map); new_map->set_is_observed(); } JSObject::MigrateToMap(object, new_map); diff --git a/src/objects.h b/src/objects.h index dad070e..be1d0c8 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6001,6 +6001,7 @@ class Map: public HeapObject { Map* transitioned_map); inline void SetTransition(int transition_index, Map* target); inline Map* GetTransition(int transition_index); + inline int SearchTransition(Name* name); static Handle AddTransition(Handle map, Handle key, diff --git a/src/property-details.h b/src/property-details.h index 01050db..5e3fea4 100644 --- a/src/property-details.h +++ b/src/property-details.h @@ -77,9 +77,8 @@ enum PropertyType { // Only in lookup results, not in descriptors. HANDLER = 4, INTERCEPTOR = 5, - TRANSITION = 6, // Only used as a marker in LookupResult. - NONEXISTENT = 7 + NONEXISTENT = 6 }; diff --git a/src/property.cc b/src/property.cc index 591ea0b..406caec 100644 --- a/src/property.cc +++ b/src/property.cc @@ -29,59 +29,61 @@ void LookupResult::Print(FILE* out) { PrintF(out, "LookupResult:\n"); PrintF(out, " -cacheable = %s\n", IsCacheable() ? "true" : "false"); PrintF(out, " -attributes = %x\n", GetAttributes()); - switch (type()) { - case NORMAL: - PrintF(out, " -type = normal\n"); - PrintF(out, " -entry = %d", GetDictionaryEntry()); - break; - case CONSTANT: - PrintF(out, " -type = constant\n"); - PrintF(out, " -value:\n"); - GetConstant()->Print(out); - PrintF(out, "\n"); - break; - case FIELD: - PrintF(out, " -type = field\n"); - PrintF(out, " -index = %d", GetFieldIndex().field_index()); - PrintF(out, "\n"); - break; - case CALLBACKS: - PrintF(out, " -type = call backs\n"); - PrintF(out, " -callback object:\n"); - GetCallbackObject()->Print(out); - break; - case HANDLER: - PrintF(out, " -type = lookup proxy\n"); - break; - case INTERCEPTOR: - PrintF(out, " -type = lookup interceptor\n"); - break; - case TRANSITION: - switch (GetTransitionDetails().type()) { - case FIELD: - PrintF(out, " -type = map transition\n"); - PrintF(out, " -map:\n"); - GetTransitionTarget()->Print(out); - PrintF(out, "\n"); - return; - case CONSTANT: - PrintF(out, " -type = constant property transition\n"); - PrintF(out, " -map:\n"); - GetTransitionTarget()->Print(out); - PrintF(out, "\n"); - return; - case CALLBACKS: - PrintF(out, " -type = callbacks transition\n"); - PrintF(out, " -callback object:\n"); - GetCallbackObject()->Print(out); - return; - default: - UNREACHABLE(); - return; - } - case NONEXISTENT: - UNREACHABLE(); - break; + if (IsTransition()) { + switch (type()) { + case FIELD: + PrintF(out, " -type = map transition\n"); + PrintF(out, " -map:\n"); + GetTransitionTarget()->Print(out); + PrintF(out, "\n"); + break; + case CONSTANT: + PrintF(out, " -type = constant property transition\n"); + PrintF(out, " -map:\n"); + GetTransitionTarget()->Print(out); + PrintF(out, "\n"); + break; + case CALLBACKS: + PrintF(out, " -type = callbacks transition\n"); + PrintF(out, " -callback object:\n"); + GetCallbackObject()->Print(out); + break; + default: + UNREACHABLE(); + break; + } + } else { + switch (type()) { + case NORMAL: + PrintF(out, " -type = normal\n"); + PrintF(out, " -entry = %d", GetDictionaryEntry()); + break; + case CONSTANT: + PrintF(out, " -type = constant\n"); + PrintF(out, " -value:\n"); + GetConstant()->Print(out); + PrintF(out, "\n"); + break; + case FIELD: + PrintF(out, " -type = field\n"); + PrintF(out, " -index = %d", GetFieldIndex().field_index()); + PrintF(out, "\n"); + break; + case CALLBACKS: + PrintF(out, " -type = call backs\n"); + PrintF(out, " -callback object:\n"); + GetCallbackObject()->Print(out); + break; + case HANDLER: + PrintF(out, " -type = lookup proxy\n"); + break; + case INTERCEPTOR: + PrintF(out, " -type = lookup interceptor\n"); + break; + case NONEXISTENT: + UNREACHABLE(); + break; + } } } diff --git a/src/property.h b/src/property.h index cfdf9c7..087e0a3 100644 --- a/src/property.h +++ b/src/property.h @@ -180,16 +180,15 @@ class LookupResult V8_FINAL BASE_EMBEDDED { bool CanHoldValue(Handle value) { if (IsNormal()) return true; - ASSERT(!IsTransition()); return value->FitsRepresentation(details_.representation()); } void TransitionResult(JSObject* holder, Map* target) { lookup_type_ = TRANSITION_TYPE; - details_ = PropertyDetails(NONE, TRANSITION, Representation::None()); + number_ = target->LastAdded(); + details_ = target->instance_descriptors()->GetDetails(number_); holder_ = holder; transition_ = target; - number_ = 0xAAAA; } void DictionaryResult(JSObject* holder, int entry) { @@ -239,20 +238,17 @@ class LookupResult V8_FINAL BASE_EMBEDDED { Representation representation() const { ASSERT(IsFound()); - ASSERT(!IsTransition()); ASSERT(details_.type() != NONEXISTENT); return details_.representation(); } PropertyAttributes GetAttributes() const { - ASSERT(!IsTransition()); ASSERT(IsFound()); ASSERT(details_.type() != NONEXISTENT); return details_.attributes(); } PropertyDetails GetPropertyDetails() const { - ASSERT(!IsTransition()); return details_; } @@ -264,38 +260,40 @@ class LookupResult V8_FINAL BASE_EMBEDDED { // Property callbacks does not include transitions to callbacks. bool IsPropertyCallbacks() const { ASSERT(!(details_.type() == CALLBACKS && !IsFound())); - return details_.type() == CALLBACKS; + return !IsTransition() && details_.type() == CALLBACKS; } bool IsReadOnly() const { ASSERT(IsFound()); - ASSERT(!IsTransition()); ASSERT(details_.type() != NONEXISTENT); return details_.IsReadOnly(); } bool IsField() const { ASSERT(!(details_.type() == FIELD && !IsFound())); - return details_.type() == FIELD; + return IsDescriptorOrDictionary() && type() == FIELD; } bool IsNormal() const { ASSERT(!(details_.type() == NORMAL && !IsFound())); - return details_.type() == NORMAL; + return IsDescriptorOrDictionary() && type() == NORMAL; } bool IsConstant() const { ASSERT(!(details_.type() == CONSTANT && !IsFound())); - return details_.type() == CONSTANT; + return IsDescriptorOrDictionary() && type() == CONSTANT; } bool IsConstantFunction() const { - return IsConstant() && GetValue()->IsJSFunction(); + return IsConstant() && GetConstant()->IsJSFunction(); } bool IsDontDelete() const { return details_.IsDontDelete(); } bool IsDontEnum() const { return details_.IsDontEnum(); } bool IsFound() const { return lookup_type_ != NOT_FOUND; } + bool IsDescriptorOrDictionary() const { + return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE; + } bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; } bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; } bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; } @@ -306,20 +304,30 @@ class LookupResult V8_FINAL BASE_EMBEDDED { } bool IsDataProperty() const { - switch (type()) { - case FIELD: - case NORMAL: - case CONSTANT: - return true; - case CALLBACKS: { - Object* callback = GetCallbackObject(); - return callback->IsAccessorInfo() || callback->IsForeign(); - } - case HANDLER: - case INTERCEPTOR: - case TRANSITION: - case NONEXISTENT: + switch (lookup_type_) { + case NOT_FOUND: + case TRANSITION_TYPE: + case HANDLER_TYPE: + case INTERCEPTOR_TYPE: return false; + + case DESCRIPTOR_TYPE: + case DICTIONARY_TYPE: + switch (type()) { + case FIELD: + case NORMAL: + case CONSTANT: + return true; + case CALLBACKS: { + Object* callback = GetCallbackObject(); + return callback->IsAccessorInfo() || callback->IsForeign(); + } + case HANDLER: + case INTERCEPTOR: + case NONEXISTENT: + UNREACHABLE(); + return false; + } } UNREACHABLE(); return false; @@ -329,45 +337,52 @@ class LookupResult V8_FINAL BASE_EMBEDDED { void DisallowCaching() { cacheable_ = false; } Object* GetLazyValue() const { - switch (type()) { - case FIELD: - return holder()->RawFastPropertyAt(GetFieldIndex().field_index()); - case NORMAL: { - Object* value; - value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); - if (holder()->IsGlobalObject()) { - value = PropertyCell::cast(value)->value(); - } - return value; - } - case CONSTANT: - return GetConstant(); - case CALLBACKS: - case HANDLER: - case INTERCEPTOR: - case TRANSITION: - case NONEXISTENT: + switch (lookup_type_) { + case NOT_FOUND: + case TRANSITION_TYPE: + case HANDLER_TYPE: + case INTERCEPTOR_TYPE: return isolate()->heap()->the_hole_value(); + + case DESCRIPTOR_TYPE: + case DICTIONARY_TYPE: + switch (type()) { + case FIELD: + return holder()->RawFastPropertyAt(GetFieldIndex().field_index()); + case NORMAL: { + Object* value = holder()->property_dictionary()->ValueAt( + GetDictionaryEntry()); + if (holder()->IsGlobalObject()) { + value = PropertyCell::cast(value)->value(); + } + return value; + } + case CONSTANT: + return GetConstant(); + case CALLBACKS: + return isolate()->heap()->the_hole_value(); + case HANDLER: + case INTERCEPTOR: + case NONEXISTENT: + UNREACHABLE(); + return NULL; + } } UNREACHABLE(); return NULL; } Map* GetTransitionTarget() const { - return transition_; - } - - PropertyDetails GetTransitionDetails() const { ASSERT(IsTransition()); - return transition_->GetLastDescriptorDetails(); + return transition_; } bool IsTransitionToField() const { - return IsTransition() && GetTransitionDetails().type() == FIELD; + return IsTransition() && details_.type() == FIELD; } bool IsTransitionToConstant() const { - return IsTransition() && GetTransitionDetails().type() == CONSTANT; + return IsTransition() && details_.type() == CONSTANT; } int GetDescriptorIndex() const { @@ -376,7 +391,8 @@ class LookupResult V8_FINAL BASE_EMBEDDED { } PropertyIndex GetFieldIndex() const { - ASSERT(lookup_type_ == DESCRIPTOR_TYPE); + ASSERT(lookup_type_ == DESCRIPTOR_TYPE || + lookup_type_ == TRANSITION_TYPE); return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map())); } @@ -409,7 +425,8 @@ class LookupResult V8_FINAL BASE_EMBEDDED { } Object* GetCallbackObject() const { - ASSERT(type() == CALLBACKS && !IsTransition()); + ASSERT(!IsTransition()); + ASSERT(type() == CALLBACKS); return GetValue(); } @@ -420,6 +437,8 @@ class LookupResult V8_FINAL BASE_EMBEDDED { Object* GetValue() const { if (lookup_type_ == DESCRIPTOR_TYPE) { return GetValueFromMap(holder()->map()); + } else if (lookup_type_ == TRANSITION_TYPE) { + return GetValueFromMap(transition_); } // In the dictionary case, the data is held in the value field. ASSERT(lookup_type_ == DICTIONARY_TYPE); @@ -427,13 +446,15 @@ class LookupResult V8_FINAL BASE_EMBEDDED { } Object* GetValueFromMap(Map* map) const { - ASSERT(lookup_type_ == DESCRIPTOR_TYPE); + ASSERT(lookup_type_ == DESCRIPTOR_TYPE || + lookup_type_ == TRANSITION_TYPE); ASSERT(number_ < map->NumberOfOwnDescriptors()); return map->instance_descriptors()->GetValue(number_); } int GetFieldIndexFromMap(Map* map) const { - ASSERT(lookup_type_ == DESCRIPTOR_TYPE); + ASSERT(lookup_type_ == DESCRIPTOR_TYPE || + lookup_type_ == TRANSITION_TYPE); ASSERT(number_ < map->NumberOfOwnDescriptors()); return map->instance_descriptors()->GetFieldIndex(number_); } diff --git a/src/runtime.cc b/src/runtime.cc index 7139f2f..959a042 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -5217,23 +5217,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) { CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); LookupResult lookup(isolate); object->LookupRealNamedProperty(*key, &lookup); - if (!lookup.IsFound()) return isolate->heap()->undefined_value(); - switch (lookup.type()) { - case NORMAL: - return lookup.holder()->GetNormalizedProperty(&lookup); - case FIELD: - return lookup.holder()->FastPropertyAt( - lookup.representation(), - lookup.GetFieldIndex().field_index()); - case CONSTANT: - return lookup.GetConstant(); - case CALLBACKS: - case HANDLER: - case INTERCEPTOR: - case TRANSITION: - return isolate->heap()->undefined_value(); - case NONEXISTENT: - UNREACHABLE(); + if (lookup.IsFound() && !lookup.IsTransition()) { + switch (lookup.type()) { + case NORMAL: + return lookup.holder()->GetNormalizedProperty(&lookup); + case FIELD: + return lookup.holder()->FastPropertyAt( + lookup.representation(), + lookup.GetFieldIndex().field_index()); + case CONSTANT: + return lookup.GetConstant(); + case CALLBACKS: + case HANDLER: + case INTERCEPTOR: + break; + case NONEXISTENT: + UNREACHABLE(); + } } return isolate->heap()->undefined_value(); } @@ -10783,6 +10783,7 @@ static MaybeObject* DebugLookupResultValue(Heap* heap, LookupResult* result, bool* caught_exception) { Object* value; + if (result->IsTransition()) return heap->undefined_value(); switch (result->type()) { case NORMAL: value = result->holder()->GetNormalizedProperty(result); @@ -10826,7 +10827,6 @@ static MaybeObject* DebugLookupResultValue(Heap* heap, } } case INTERCEPTOR: - case TRANSITION: return heap->undefined_value(); case HANDLER: case NONEXISTENT: -- 2.7.4