From: jochen@chromium.org Date: Thu, 17 Jul 2014 09:44:37 +0000 (+0000) Subject: Remove JSReceiver::GetPrototype and replace it with PrototypeIterator calls X-Git-Tag: upstream/4.7.83~8188 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fe558594b9f7b064dfe50345c27e0d5eaba0d623;p=platform%2Fupstream%2Fv8.git Remove JSReceiver::GetPrototype and replace it with PrototypeIterator calls BUG=none R=verwaest@chromium.org LOG=n Review URL: https://codereview.chromium.org/390323002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22442 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/accessors.cc b/src/accessors.cc index 13c2803..182f0f6 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -846,8 +846,8 @@ static Handle GetFunctionPrototype(Isolate* isolate, JSFunction* function_raw = FindInstanceOf(isolate, *receiver); if (function_raw == NULL) return isolate->factory()->undefined_value(); while (!function_raw->should_have_prototype()) { - function_raw = FindInstanceOf(isolate, - function_raw->GetPrototype()); + PrototypeIterator iter(isolate, function_raw); + function_raw = FindInstanceOf(isolate, iter.GetCurrent()); // There has to be one because we hit the getter. ASSERT(function_raw != NULL); } diff --git a/src/api.cc b/src/api.cc index 15911e0..c7bc074 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3193,14 +3193,17 @@ Local v8::Object::FindInstanceInPrototypeChain( "v8::Object::FindInstanceInPrototypeChain()", return Local()); ENTER_V8(isolate); - i::JSObject* object = *Utils::OpenHandle(this); + i::PrototypeIterator iter(isolate, *Utils::OpenHandle(this), + i::PrototypeIterator::START_AT_RECEIVER); i::FunctionTemplateInfo* tmpl_info = *Utils::OpenHandle(*tmpl); - while (!tmpl_info->IsTemplateFor(object)) { - i::Object* prototype = object->GetPrototype(); - if (!prototype->IsJSObject()) return Local(); - object = i::JSObject::cast(prototype); + while (!tmpl_info->IsTemplateFor(iter.GetCurrent())) { + iter.Advance(); + if (iter.IsAtEnd()) { + return Local(); + } } - return Utils::ToLocal(i::Handle(object)); + return Utils::ToLocal( + i::handle(i::JSObject::cast(iter.GetCurrent()), isolate)); } diff --git a/src/builtins.cc b/src/builtins.cc index ddaea59..4acb1d7 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -254,12 +254,15 @@ static bool ArrayPrototypeHasNoElements(Heap* heap, // fields. if (array_proto->elements() != heap->empty_fixed_array()) return false; // Object.prototype - Object* proto = array_proto->GetPrototype(); - if (proto == heap->null_value()) return false; - array_proto = JSObject::cast(proto); + PrototypeIterator iter(heap->isolate(), array_proto); + if (iter.IsAtEnd()) { + return false; + } + array_proto = JSObject::cast(iter.GetCurrent()); if (array_proto != native_context->initial_object_prototype()) return false; if (array_proto->elements() != heap->empty_fixed_array()) return false; - return array_proto->GetPrototype()->IsNull(); + iter.Advance(); + return iter.IsAtEnd(); } @@ -332,7 +335,8 @@ static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, Context* native_context = heap->isolate()->context()->native_context(); JSObject* array_proto = JSObject::cast(native_context->array_function()->prototype()); - return receiver->GetPrototype() == array_proto && + PrototypeIterator iter(heap->isolate(), receiver); + return iter.GetCurrent() == array_proto && ArrayPrototypeHasNoElements(heap, native_context, array_proto); } @@ -1000,9 +1004,9 @@ BUILTIN(ArrayConcat) { bool is_holey = false; for (int i = 0; i < n_arguments; i++) { Object* arg = args[i]; - if (!arg->IsJSArray() || - !JSArray::cast(arg)->HasFastElements() || - JSArray::cast(arg)->GetPrototype() != array_proto) { + PrototypeIterator iter(isolate, arg); + if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() || + iter.GetCurrent() != array_proto) { AllowHeapAllocation allow_allocation; return CallJsBuiltin(isolate, "ArrayConcatJS", args); } diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index a730b48..d8dff9d 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -459,9 +459,11 @@ void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) { reinterpret_cast(object)); } if (object->IsJSGlobalProxy()) { - Object* proto = object->GetPrototype(); - CHECK(proto->IsJSGlobalObject()); - Context* native_context = GlobalObject::cast(proto)->native_context(); + PrototypeIterator iter(object->GetIsolate(), object); + // TODO(verwaest): This CHECK will be hit if the global proxy is detached. + CHECK(iter.GetCurrent()->IsJSGlobalObject()); + Context* native_context = + GlobalObject::cast(iter.GetCurrent())->native_context(); MarkAllCodeForContext(native_context); DeoptimizeMarkedCodeForContext(native_context); } else if (object->IsGlobalObject()) { diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index 6229386..f085622 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -1164,8 +1164,8 @@ void V8HeapExplorer::ExtractJSObjectReferences( ExtractPropertyReferences(js_obj, entry); ExtractElementReferences(js_obj, entry); ExtractInternalReferences(js_obj, entry); - SetPropertyReference( - obj, entry, heap_->proto_string(), js_obj->GetPrototype()); + PrototypeIterator iter(heap_->isolate(), js_obj); + SetPropertyReference(obj, entry, heap_->proto_string(), iter.GetCurrent()); if (obj->IsJSFunction()) { JSFunction* js_fun = JSFunction::cast(js_obj); Object* proto_or_map = js_fun->prototype_or_initial_map(); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 018e50f..9dc40f0 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -6828,14 +6828,16 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( // monomorphic stores need a prototype chain check because shape // changes could allow callbacks on elements in the chain that // aren't compatible with monomorphic keyed stores. - Handle prototype(JSObject::cast(map->prototype())); - JSObject* holder = JSObject::cast(map->prototype()); - while (!holder->GetPrototype()->IsNull()) { - holder = JSObject::cast(holder->GetPrototype()); + PrototypeIterator iter(map); + JSObject* holder = NULL; + while (!iter.IsAtEnd()) { + holder = JSObject::cast(*PrototypeIterator::GetCurrent(iter)); + iter.Advance(); } + ASSERT(holder && holder->IsJSObject()); - BuildCheckPrototypeMaps(prototype, - Handle(JSObject::cast(holder))); + BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())), + Handle(holder)); } LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); @@ -7307,14 +7309,19 @@ HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle constant) { HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle prototype, Handle holder) { - while (holder.is_null() || !prototype.is_identical_to(holder)) { - BuildConstantMapCheck(prototype); - Object* next_prototype = prototype->GetPrototype(); - if (next_prototype->IsNull()) return NULL; - CHECK(next_prototype->IsJSObject()); - prototype = handle(JSObject::cast(next_prototype)); - } - return BuildConstantMapCheck(prototype); + PrototypeIterator iter(isolate(), prototype, + PrototypeIterator::START_AT_RECEIVER); + while (holder.is_null() || + !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) { + BuildConstantMapCheck( + Handle::cast(PrototypeIterator::GetCurrent(iter))); + iter.Advance(); + if (iter.IsAtEnd()) { + return NULL; + } + } + return BuildConstantMapCheck( + Handle::cast(PrototypeIterator::GetCurrent(iter))); } diff --git a/src/ic.cc b/src/ic.cc index 7fee8b5..e312a85 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -223,13 +223,13 @@ static void LookupForRead(Handle object, return; } - Handle proto(holder->GetPrototype(), lookup->isolate()); - if (proto->IsNull()) { + PrototypeIterator iter(lookup->isolate(), holder); + if (iter.IsAtEnd()) { ASSERT(!lookup->IsFound()); return; } - object = proto; + object = PrototypeIterator::GetCurrent(iter); } } @@ -1233,7 +1233,8 @@ static bool LookupForWrite(Handle receiver, // goes into the runtime if access checks are needed, so this is always // safe. if (receiver->IsJSGlobalProxy()) { - return lookup->holder() == receiver->GetPrototype(); + PrototypeIterator iter(lookup->isolate(), receiver); + return lookup->holder() == *PrototypeIterator::GetCurrent(iter); } // Currently normal holders in the prototype chain are not supported. They // would require a runtime positive lookup and verification that the details @@ -1453,9 +1454,12 @@ Handle StoreIC::CompileHandler(LookupResult* lookup, // 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); + PrototypeIterator iter(isolate(), receiver); + Handle global = + receiver->IsJSGlobalProxy() + ? Handle::cast( + PrototypeIterator::GetCurrent(iter)) + : Handle::cast(receiver); Handle cell(global->GetPropertyCell(lookup), isolate()); Handle union_type = PropertyCell::UpdatedType(cell, value); StoreGlobalStub stub( diff --git a/src/isolate.cc b/src/isolate.cc index aa37711..189ea94 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -2156,13 +2156,16 @@ bool Isolate::IsFastArrayConstructorPrototypeChainIntact() { // Check that the object prototype hasn't been altered WRT empty elements. JSObject* initial_object_proto = JSObject::cast(*initial_object_prototype()); - Object* root_array_map_proto = initial_array_proto->GetPrototype(); - if (root_array_map_proto != initial_object_proto) return false; + PrototypeIterator iter(this, initial_array_proto); + if (iter.IsAtEnd() || iter.GetCurrent() != initial_object_proto) { + return false; + } if (initial_object_proto->elements() != heap()->empty_fixed_array()) { return false; } - return initial_object_proto->GetPrototype()->IsNull(); + iter.Advance(); + return iter.IsAtEnd(); } diff --git a/src/objects-inl.h b/src/objects-inl.h index b81921e..b01c49d 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -26,6 +26,7 @@ #include "src/objects.h" #include "src/objects-visiting.h" #include "src/property.h" +#include "src/prototype.h" #include "src/spaces.h" #include "src/store-buffer.h" #include "src/transitions-inl.h" @@ -6617,11 +6618,6 @@ bool String::AsArrayIndex(uint32_t* index) { } -Object* JSReceiver::GetPrototype() const { - return map()->prototype(); -} - - Object* JSReceiver::GetConstructor() { return map()->constructor(); } @@ -6674,7 +6670,9 @@ bool JSGlobalObject::IsDetached() { bool JSGlobalProxy::IsDetachedFrom(GlobalObject* global) const { - return GetPrototype() != global; + const PrototypeIterator iter(this->GetIsolate(), + const_cast(this)); + return iter.GetCurrent() != global; } diff --git a/src/objects-printer.cc b/src/objects-printer.cc index e6b2e6b..02944df 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -389,10 +389,11 @@ void JSObject::JSObjectPrint(OStream& os) { // NOLINT HeapObject::PrintHeader(os, "JSObject"); // Don't call GetElementsKind, its validation code can cause the printer to // fail when debugging. + PrototypeIterator iter(GetIsolate(), this); os << " - map = " << reinterpret_cast(map()) << " [" << ElementsKindToString(this->map()->elements_kind()) - << "]\n - prototype = " << reinterpret_cast(GetPrototype()) << "\n" - << " {\n"; + << "]\n - prototype = " << reinterpret_cast(iter.GetCurrent()) + << "\n {\n"; PrintProperties(os); PrintTransitions(os); PrintElements(os); diff --git a/src/objects.cc b/src/objects.cc index 6c60fb3..cead2dd 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -3446,10 +3446,11 @@ void JSObject::LookupOwnRealNamedProperty(Handle name, LookupResult* result) { DisallowHeapAllocation no_gc; if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); - if (proto->IsNull()) return result->NotFound(); - ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->LookupOwnRealNamedProperty(name, result); + PrototypeIterator iter(GetIsolate(), this); + if (iter.IsAtEnd()) return result->NotFound(); + ASSERT(iter.GetCurrent()->IsJSGlobalObject()); + return JSObject::cast(iter.GetCurrent()) + ->LookupOwnRealNamedProperty(name, result); } if (HasFastProperties()) { @@ -4064,11 +4065,12 @@ MaybeHandle JSObject::SetPropertyForResult( } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return value; - ASSERT(proto->IsJSGlobalObject()); - return SetPropertyForResult(Handle::cast(proto), lookup, name, - value, strict_mode, store_mode); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return value; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return SetPropertyForResult( + Handle::cast(PrototypeIterator::GetCurrent(iter)), lookup, + name, value, strict_mode, store_mode); } ASSERT(!lookup->IsFound() || lookup->holder() == *object || @@ -4219,12 +4221,12 @@ MaybeHandle JSObject::SetOwnPropertyIgnoreAttributes( } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return value; - ASSERT(proto->IsJSGlobalObject()); - return SetOwnPropertyIgnoreAttributes(Handle::cast(proto), name, - value, attributes, mode, - extensibility_check); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return value; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return SetOwnPropertyIgnoreAttributes( + Handle::cast(PrototypeIterator::GetCurrent(iter)), name, + value, attributes, mode, extensibility_check); } if (lookup.IsInterceptor() || @@ -4454,11 +4456,12 @@ PropertyAttributes JSObject::GetElementAttributeWithReceiver( } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return ABSENT; - ASSERT(proto->IsJSGlobalObject()); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return ABSENT; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); return JSObject::GetElementAttributeWithReceiver( - Handle::cast(proto), receiver, index, check_prototype); + Handle::cast(PrototypeIterator::GetCurrent(iter)), receiver, + index, check_prototype); } // Check for lookup interceptor except when bootstrapping. @@ -4526,15 +4529,17 @@ PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor( if (!check_prototype) return ABSENT; - Handle proto(object->GetPrototype(), object->GetIsolate()); - if (proto->IsJSProxy()) { + PrototypeIterator iter(object->GetIsolate(), object); + if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { // We need to follow the spec and simulate a call to [[GetOwnProperty]]. return JSProxy::GetElementAttributeWithHandler( - Handle::cast(proto), receiver, index); + Handle::cast(PrototypeIterator::GetCurrent(iter)), receiver, + index); } - if (proto->IsNull()) return ABSENT; + if (iter.IsAtEnd()) return ABSENT; return GetElementAttributeWithReceiver( - Handle::cast(proto), receiver, index, true); + Handle::cast(PrototypeIterator::GetCurrent(iter)), receiver, + index, true); } @@ -5012,11 +5017,11 @@ Object* JSObject::GetHiddenProperty(Handle key) { // JSGlobalProxies store their hash internally. ASSERT(*key != GetHeap()->identity_hash_string()); // For a proxy, use the prototype as target object. - Object* proxy_parent = GetPrototype(); + PrototypeIterator iter(GetIsolate(), this); // If the proxy is detached, return undefined. - if (proxy_parent->IsNull()) return GetHeap()->the_hole_value(); - ASSERT(proxy_parent->IsJSGlobalObject()); - return JSObject::cast(proxy_parent)->GetHiddenProperty(key); + if (iter.IsAtEnd()) return GetHeap()->the_hole_value(); + ASSERT(iter.GetCurrent()->IsJSGlobalObject()); + return JSObject::cast(iter.GetCurrent())->GetHiddenProperty(key); } ASSERT(!IsJSGlobalProxy()); Object* inline_value = GetHiddenPropertiesHashTable(); @@ -5048,11 +5053,13 @@ Handle JSObject::SetHiddenProperty(Handle object, // JSGlobalProxies store their hash internally. ASSERT(*key != *isolate->factory()->identity_hash_string()); // For a proxy, use the prototype as target object. - Handle proxy_parent(object->GetPrototype(), isolate); + PrototypeIterator iter(isolate, object); // If the proxy is detached, return undefined. - if (proxy_parent->IsNull()) return isolate->factory()->undefined_value(); - ASSERT(proxy_parent->IsJSGlobalObject()); - return SetHiddenProperty(Handle::cast(proxy_parent), key, value); + if (iter.IsAtEnd()) return isolate->factory()->undefined_value(); + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return SetHiddenProperty( + Handle::cast(PrototypeIterator::GetCurrent(iter)), key, + value); } ASSERT(!object->IsJSGlobalProxy()); @@ -5087,10 +5094,11 @@ void JSObject::DeleteHiddenProperty(Handle object, Handle key) { ASSERT(key->IsUniqueName()); if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return; - ASSERT(proto->IsJSGlobalObject()); - return DeleteHiddenProperty(Handle::cast(proto), key); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return DeleteHiddenProperty( + Handle::cast(PrototypeIterator::GetCurrent(iter)), key); } Object* inline_value = object->GetHiddenPropertiesHashTable(); @@ -5320,10 +5328,12 @@ MaybeHandle JSObject::DeleteElement(Handle object, } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return factory->false_value(); - ASSERT(proto->IsJSGlobalObject()); - return DeleteElement(Handle::cast(proto), index, mode); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return factory->false_value(); + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return DeleteElement( + Handle::cast(PrototypeIterator::GetCurrent(iter)), index, + mode); } Handle old_value; @@ -5375,11 +5385,12 @@ MaybeHandle JSObject::DeleteProperty(Handle object, } if (object->IsJSGlobalProxy()) { - Object* proto = object->GetPrototype(); - if (proto->IsNull()) return isolate->factory()->false_value(); - ASSERT(proto->IsJSGlobalObject()); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return isolate->factory()->false_value(); + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); return JSGlobalObject::DeleteProperty( - handle(JSGlobalObject::cast(proto)), name, mode); + Handle::cast(PrototypeIterator::GetCurrent(iter)), name, + mode); } uint32_t index = 0; @@ -5608,10 +5619,11 @@ MaybeHandle JSObject::PreventExtensions(Handle object) { } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return object; - ASSERT(proto->IsJSGlobalObject()); - return PreventExtensions(Handle::cast(proto)); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return object; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return PreventExtensions( + Handle::cast(PrototypeIterator::GetCurrent(iter))); } // It's not possible to seal objects with external array elements @@ -5691,10 +5703,10 @@ MaybeHandle JSObject::Freeze(Handle object) { } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return object; - ASSERT(proto->IsJSGlobalObject()); - return Freeze(Handle::cast(proto)); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return object; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return Freeze(Handle::cast(PrototypeIterator::GetCurrent(iter))); } // It's not possible to freeze objects with external array elements @@ -6079,12 +6091,11 @@ Handle JSObject::GetDataProperty(Handle object, // - This object has no elements. // - No prototype has enumerable properties/elements. bool JSReceiver::IsSimpleEnum() { - Heap* heap = GetHeap(); - for (Object* o = this; - o != heap->null_value(); - o = JSObject::cast(o)->GetPrototype()) { - if (!o->IsJSObject()) return false; - JSObject* curr = JSObject::cast(o); + for (PrototypeIterator iter(GetIsolate(), this, + PrototypeIterator::START_AT_RECEIVER); + !iter.IsAtEnd(); iter.Advance()) { + if (!iter.GetCurrent()->IsJSObject()) return false; + JSObject* curr = JSObject::cast(iter.GetCurrent()); int enum_length = curr->map()->EnumLength(); if (enum_length == kInvalidEnumCacheSentinel) return false; if (curr->IsAccessCheckNeeded()) return false; @@ -6152,11 +6163,11 @@ void JSReceiver::LookupOwn( ASSERT(name->IsName()); if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); - if (proto->IsNull()) return result->NotFound(); - ASSERT(proto->IsJSGlobalObject()); - return JSReceiver::cast(proto)->LookupOwn( - name, result, search_hidden_prototypes); + PrototypeIterator iter(GetIsolate(), this); + if (iter.IsAtEnd()) return result->NotFound(); + ASSERT(iter.GetCurrent()->IsJSGlobalObject()); + return JSReceiver::cast(iter.GetCurrent()) + ->LookupOwn(name, result, search_hidden_prototypes); } if (IsJSProxy()) { @@ -6182,9 +6193,9 @@ void JSReceiver::LookupOwn( js_object->LookupOwnRealNamedProperty(name, result); if (result->IsFound() || !search_hidden_prototypes) return; - Object* proto = js_object->GetPrototype(); - if (!proto->IsJSReceiver()) return; - JSReceiver* receiver = JSReceiver::cast(proto); + PrototypeIterator iter(GetIsolate(), js_object); + if (!iter.GetCurrent()->IsJSReceiver()) return; + JSReceiver* receiver = JSReceiver::cast(iter.GetCurrent()); if (receiver->map()->is_hidden_prototype()) { receiver->LookupOwn(name, result, search_hidden_prototypes); } @@ -6194,11 +6205,10 @@ void JSReceiver::LookupOwn( void JSReceiver::Lookup(Handle name, LookupResult* result) { DisallowHeapAllocation no_gc; // Ecma-262 3rd 8.6.2.4 - Handle null_value = GetIsolate()->factory()->null_value(); - for (Object* current = this; - current != *null_value; - current = JSObject::cast(current)->GetPrototype()) { - JSReceiver::cast(current)->LookupOwn(name, result, false); + for (PrototypeIterator iter(GetIsolate(), this, + PrototypeIterator::START_AT_RECEIVER); + !iter.IsAtEnd(); iter.Advance()) { + JSReceiver::cast(iter.GetCurrent())->LookupOwn(name, result, false); if (result->IsFound()) return; } result->NotFound(); @@ -6678,14 +6688,11 @@ void JSObject::DefineAccessor(Handle object, } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return; - ASSERT(proto->IsJSGlobalObject()); - DefineAccessor(Handle::cast(proto), - name, - getter, - setter, - attributes); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + DefineAccessor(Handle::cast(PrototypeIterator::GetCurrent(iter)), + name, getter, setter, attributes); return; } @@ -6854,10 +6861,11 @@ MaybeHandle JSObject::SetAccessor(Handle object, } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return object; - ASSERT(proto->IsJSGlobalObject()); - return SetAccessor(Handle::cast(proto), info); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return object; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return SetAccessor( + Handle::cast(PrototypeIterator::GetCurrent(iter)), info); } // Make sure that the top context does not change when doing callbacks or @@ -6938,11 +6946,14 @@ MaybeHandle JSObject::GetAccessor(Handle object, // Make the lookup and include prototypes. uint32_t index = 0; if (name->AsArrayIndex(&index)) { - for (Handle obj = object; - !obj->IsNull(); - obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) { - if (obj->IsJSObject() && JSObject::cast(*obj)->HasDictionaryElements()) { - JSObject* js_object = JSObject::cast(*obj); + for (PrototypeIterator iter(isolate, object, + PrototypeIterator::START_AT_RECEIVER); + !iter.IsAtEnd(); iter.Advance()) { + if (PrototypeIterator::GetCurrent(iter)->IsJSObject() && + JSObject::cast(*PrototypeIterator::GetCurrent(iter)) + ->HasDictionaryElements()) { + JSObject* js_object = + JSObject::cast(*PrototypeIterator::GetCurrent(iter)); SeededNumberDictionary* dictionary = js_object->element_dictionary(); int entry = dictionary->FindEntry(index); if (entry != SeededNumberDictionary::kNotFound) { @@ -6956,11 +6967,12 @@ MaybeHandle JSObject::GetAccessor(Handle object, } } } else { - for (Handle obj = object; - !obj->IsNull(); - obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) { + for (PrototypeIterator iter(isolate, object, + PrototypeIterator::START_AT_RECEIVER); + !iter.IsAtEnd(); iter.Advance()) { LookupResult result(isolate); - JSReceiver::cast(*obj)->LookupOwn(name, &result); + JSReceiver::cast(*PrototypeIterator::GetCurrent(iter)) + ->LookupOwn(name, &result); if (result.IsFound()) { if (result.IsReadOnly()) return isolate->factory()->undefined_value(); if (result.IsPropertyCallbacks()) { @@ -12205,10 +12217,11 @@ MaybeHandle JSObject::GetOwnElementAccessorPair( Handle object, uint32_t index) { if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), object->GetIsolate()); - if (proto->IsNull()) return MaybeHandle(); - ASSERT(proto->IsJSGlobalObject()); - return GetOwnElementAccessorPair(Handle::cast(proto), index); + PrototypeIterator iter(object->GetIsolate(), object); + if (iter.IsAtEnd()) return MaybeHandle(); + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return GetOwnElementAccessorPair( + Handle::cast(PrototypeIterator::GetCurrent(iter)), index); } // Check for lookup interceptor. @@ -12811,13 +12824,12 @@ MaybeHandle JSObject::SetElement(Handle object, } if (object->IsJSGlobalProxy()) { - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return value; - ASSERT(proto->IsJSGlobalObject()); - return SetElement(Handle::cast(proto), index, value, attributes, - strict_mode, - check_prototype, - set_mode); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return value; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return SetElement( + Handle::cast(PrototypeIterator::GetCurrent(iter)), index, + value, attributes, strict_mode, check_prototype, set_mode); } // Don't allow element properties to be redefined for external arrays. @@ -13315,9 +13327,10 @@ MaybeHandle JSObject::GetElementWithInterceptor( Object); if (!result->IsTheHole()) return result; - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return isolate->factory()->undefined_value(); - return Object::GetElementWithReceiver(isolate, proto, receiver, index); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return isolate->factory()->undefined_value(); + return Object::GetElementWithReceiver( + isolate, PrototypeIterator::GetCurrent(iter), receiver, index); } @@ -13678,10 +13691,11 @@ bool JSObject::HasRealElementProperty(Handle object, uint32_t index) { if (object->IsJSGlobalProxy()) { HandleScope scope(isolate); - Handle proto(object->GetPrototype(), isolate); - if (proto->IsNull()) return false; - ASSERT(proto->IsJSGlobalObject()); - return HasRealElementProperty(Handle::cast(proto), index); + PrototypeIterator iter(isolate, object); + if (iter.IsAtEnd()) return false; + ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); + return HasRealElementProperty( + Handle::cast(PrototypeIterator::GetCurrent(iter)), index); } return GetElementAttributeWithoutInterceptor( diff --git a/src/objects.h b/src/objects.h index d33bead..ec6f605 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1989,9 +1989,6 @@ class JSReceiver: public HeapObject { Handle object, uint32_t index); - // Return the object's prototype (might be Heap::null_value()). - inline Object* GetPrototype() const; - // Return the constructor function (may be Heap::null_value()). inline Object* GetConstructor(); diff --git a/src/prototype.h b/src/prototype.h index aebdcbc..586df56 100644 --- a/src/prototype.h +++ b/src/prototype.h @@ -52,6 +52,11 @@ class PrototypeIterator { : did_jump_to_prototype_chain_(true), object_(receiver_map->prototype()), isolate_(receiver_map->GetIsolate()) {} + explicit PrototypeIterator(Handle receiver_map) + : did_jump_to_prototype_chain_(true), + object_(NULL), + handle_(handle(receiver_map->prototype(), receiver_map->GetIsolate())), + isolate_(receiver_map->GetIsolate()) {} ~PrototypeIterator() {} Object* GetCurrent() const { diff --git a/src/runtime.cc b/src/runtime.cc index 8c3f2ac..17bc34a 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2012,10 +2012,10 @@ RUNTIME_FUNCTION(Runtime_IsExtensible) { ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSObject, obj, 0); if (obj->IsJSGlobalProxy()) { - Object* proto = obj->GetPrototype(); - if (proto->IsNull()) return isolate->heap()->false_value(); - ASSERT(proto->IsJSGlobalObject()); - obj = JSObject::cast(proto); + PrototypeIterator iter(isolate, obj); + if (iter.IsAtEnd()) return isolate->heap()->false_value(); + ASSERT(iter.GetCurrent()->IsJSGlobalObject()); + obj = JSObject::cast(iter.GetCurrent()); } return isolate->heap()->ToBoolean(obj->map()->is_extensible()); } @@ -4949,7 +4949,8 @@ RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) { if (js_object->IsJSGlobalProxy()) { // Since the result is a property, the prototype will exist so // we don't have to check for null. - js_object = Handle(JSObject::cast(js_object->GetPrototype())); + PrototypeIterator iter(isolate, js_object); + js_object = Handle::cast(PrototypeIterator::GetCurrent(iter)); } if (attr != lookup.GetAttributes() || @@ -5470,12 +5471,16 @@ static Object* HasOwnPropertyImplementation(Isolate* isolate, // Handle hidden prototypes. If there's a hidden prototype above this thing // then we have to check it for properties, because they are supposed to // look like they are on this object. - Handle proto(object->GetPrototype(), isolate); - if (proto->IsJSObject() && - Handle::cast(proto)->map()->is_hidden_prototype()) { - return HasOwnPropertyImplementation(isolate, - Handle::cast(proto), - key); + PrototypeIterator iter(isolate, object); + if (!iter.IsAtEnd() && + Handle::cast(PrototypeIterator::GetCurrent(iter)) + ->map() + ->is_hidden_prototype()) { + // TODO(verwaest): The recursion is not necessary for keys that are array + // indicies. Removing this. + return HasOwnPropertyImplementation( + isolate, Handle::cast(PrototypeIterator::GetCurrent(iter)), + key); } RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return isolate->heap()->false_value(); @@ -5613,11 +5618,9 @@ RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) { // is prototype for. static int OwnPrototypeChainLength(JSObject* obj) { int count = 1; - Object* proto = obj->GetPrototype(); - while (proto->IsJSObject() && - JSObject::cast(proto)->map()->is_hidden_prototype()) { + for (PrototypeIterator iter(obj->GetIsolate(), obj); + !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) { count++; - proto = JSObject::cast(proto)->GetPrototype(); } return count; } @@ -5647,7 +5650,8 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return *isolate->factory()->NewJSArray(0); } - obj = Handle(JSObject::cast(obj->GetPrototype())); + PrototypeIterator iter(isolate, obj); + obj = Handle::cast(PrototypeIterator::GetCurrent(iter)); } // Find the number of objects making up this. @@ -5656,22 +5660,26 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { // Find the number of own properties for each of the objects. ScopedVector own_property_count(length); int total_property_count = 0; - Handle jsproto = obj; - for (int i = 0; i < length; i++) { - // Only collect names if access is permitted. - if (jsproto->IsAccessCheckNeeded() && - !isolate->MayNamedAccess( - jsproto, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { - isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS); - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); - return *isolate->factory()->NewJSArray(0); - } - int n; - n = jsproto->NumberOfOwnProperties(filter); - own_property_count[i] = n; - total_property_count += n; - if (i < length - 1) { - jsproto = Handle(JSObject::cast(jsproto->GetPrototype())); + { + PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); + for (int i = 0; i < length; i++) { + ASSERT(!iter.IsAtEnd()); + Handle jsproto = + Handle::cast(PrototypeIterator::GetCurrent(iter)); + // Only collect names if access is permitted. + if (jsproto->IsAccessCheckNeeded() && + !isolate->MayNamedAccess(jsproto, + isolate->factory()->undefined_value(), + v8::ACCESS_KEYS)) { + isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS); + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); + return *isolate->factory()->NewJSArray(0); + } + int n; + n = jsproto->NumberOfOwnProperties(filter); + own_property_count[i] = n; + total_property_count += n; + iter.Advance(); } } @@ -5680,39 +5688,41 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { isolate->factory()->NewFixedArray(total_property_count); // Get the property names. - jsproto = obj; int next_copy_index = 0; int hidden_strings = 0; - for (int i = 0; i < length; i++) { - jsproto->GetOwnPropertyNames(*names, next_copy_index, filter); - if (i > 0) { - // Names from hidden prototypes may already have been added - // for inherited function template instances. Count the duplicates - // and stub them out; the final copy pass at the end ignores holes. - for (int j = next_copy_index; - j < next_copy_index + own_property_count[i]; - j++) { - Object* name_from_hidden_proto = names->get(j); - for (int k = 0; k < next_copy_index; k++) { - if (names->get(k) != isolate->heap()->hidden_string()) { - Object* name = names->get(k); - if (name_from_hidden_proto == name) { - names->set(j, isolate->heap()->hidden_string()); - hidden_strings++; - break; + { + PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); + for (int i = 0; i < length; i++) { + ASSERT(!iter.IsAtEnd()); + Handle jsproto = + Handle::cast(PrototypeIterator::GetCurrent(iter)); + jsproto->GetOwnPropertyNames(*names, next_copy_index, filter); + if (i > 0) { + // Names from hidden prototypes may already have been added + // for inherited function template instances. Count the duplicates + // and stub them out; the final copy pass at the end ignores holes. + for (int j = next_copy_index; + j < next_copy_index + own_property_count[i]; j++) { + Object* name_from_hidden_proto = names->get(j); + for (int k = 0; k < next_copy_index; k++) { + if (names->get(k) != isolate->heap()->hidden_string()) { + Object* name = names->get(k); + if (name_from_hidden_proto == name) { + names->set(j, isolate->heap()->hidden_string()); + hidden_strings++; + break; + } } } } } - } - next_copy_index += own_property_count[i]; + next_copy_index += own_property_count[i]; - // Hidden properties only show up if the filter does not skip strings. - if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) { - hidden_strings++; - } - if (i < length - 1) { - jsproto = Handle(JSObject::cast(jsproto->GetPrototype())); + // Hidden properties only show up if the filter does not skip strings. + if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) { + hidden_strings++; + } + iter.Advance(); } } @@ -5823,10 +5833,10 @@ RUNTIME_FUNCTION(Runtime_OwnKeys) { return *isolate->factory()->NewJSArray(0); } - Handle proto(object->GetPrototype(), isolate); + PrototypeIterator iter(isolate, object); // If proxy is detached we simply return an empty array. - if (proto->IsNull()) return *isolate->factory()->NewJSArray(0); - object = Handle::cast(proto); + if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0); + object = Handle::cast(PrototypeIterator::GetCurrent(iter)); } Handle contents; @@ -10099,11 +10109,13 @@ static void CollectElementIndices(Handle object, } } - Handle prototype(object->GetPrototype(), isolate); - if (prototype->IsJSObject()) { + PrototypeIterator iter(isolate, object); + if (!iter.IsAtEnd()) { // The prototype will usually have no inherited element indices, // but we have to check. - CollectElementIndices(Handle::cast(prototype), range, indices); + CollectElementIndices( + Handle::cast(PrototypeIterator::GetCurrent(iter)), range, + indices); } } @@ -10721,8 +10733,11 @@ RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { int length = OwnPrototypeChainLength(*obj); // Try own lookup on each of the objects. - Handle jsproto = obj; + PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); for (int i = 0; i < length; i++) { + ASSERT(!iter.IsAtEnd()); + Handle jsproto = + Handle::cast(PrototypeIterator::GetCurrent(iter)); LookupResult result(isolate); jsproto->LookupOwn(name, &result); if (result.IsFound()) { @@ -10757,9 +10772,7 @@ RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { return *isolate->factory()->NewJSArrayWithElements(details); } - if (i < length - 1) { - jsproto = Handle(JSObject::cast(jsproto->GetPrototype())); - } + iter.Advance(); } return isolate->heap()->undefined_value(); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 2a3d5c3..0c9f451 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -700,8 +700,9 @@ void StubCompiler::LookupPostInterceptor(Handle holder, LookupResult* lookup) { holder->LookupOwnRealNamedProperty(name, lookup); if (lookup->IsFound()) return; - if (holder->GetPrototype()->IsNull()) return; - holder->GetPrototype()->Lookup(name, lookup); + PrototypeIterator iter(holder->GetIsolate(), holder); + if (iter.IsAtEnd()) return; + PrototypeIterator::GetCurrent(iter)->Lookup(name, lookup); } @@ -971,17 +972,18 @@ Handle StoreStubCompiler::CompileStoreTransition( __ CheckMapDeprecated(transition, scratch1(), &miss); // Check that we are allowed to write this. - if (object->GetPrototype()->IsJSObject()) { + PrototypeIterator iter(object->GetIsolate(), object); + if (!iter.IsAtEnd()) { Handle holder; // holder == object indicates that no property was found. if (lookup->holder() != *object) { holder = Handle(lookup->holder()); } else { // Find the top object. - holder = object; do { - holder = Handle(JSObject::cast(holder->GetPrototype())); - } while (holder->GetPrototype()->IsJSObject()); + holder = Handle::cast(PrototypeIterator::GetCurrent(iter)); + iter.Advance(); + } while (!iter.IsAtEnd()); } Register holder_reg = HandlerFrontendHeader(