Remove JSReceiver::GetPrototype and replace it with PrototypeIterator calls
authorjochen@chromium.org <jochen@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 17 Jul 2014 09:44:37 +0000 (09:44 +0000)
committerjochen@chromium.org <jochen@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 17 Jul 2014 09:44:37 +0000 (09:44 +0000)
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

15 files changed:
src/accessors.cc
src/api.cc
src/builtins.cc
src/deoptimizer.cc
src/heap-snapshot-generator.cc
src/hydrogen.cc
src/ic.cc
src/isolate.cc
src/objects-inl.h
src/objects-printer.cc
src/objects.cc
src/objects.h
src/prototype.h
src/runtime.cc
src/stub-cache.cc

index 13c2803..182f0f6 100644 (file)
@@ -846,8 +846,8 @@ static Handle<Object> GetFunctionPrototype(Isolate* isolate,
     JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, *receiver);
     if (function_raw == NULL) return isolate->factory()->undefined_value();
     while (!function_raw->should_have_prototype()) {
-      function_raw = FindInstanceOf<JSFunction>(isolate,
-                                                function_raw->GetPrototype());
+      PrototypeIterator iter(isolate, function_raw);
+      function_raw = FindInstanceOf<JSFunction>(isolate, iter.GetCurrent());
       // There has to be one because we hit the getter.
       ASSERT(function_raw != NULL);
     }
index 15911e0..c7bc074 100644 (file)
@@ -3193,14 +3193,17 @@ Local<Object> v8::Object::FindInstanceInPrototypeChain(
              "v8::Object::FindInstanceInPrototypeChain()",
              return Local<v8::Object>());
   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>();
-    object = i::JSObject::cast(prototype);
+  while (!tmpl_info->IsTemplateFor(iter.GetCurrent())) {
+    iter.Advance();
+    if (iter.IsAtEnd()) {
+      return Local<Object>();
+    }
   }
-  return Utils::ToLocal(i::Handle<i::JSObject>(object));
+  return Utils::ToLocal(
+      i::handle(i::JSObject::cast(iter.GetCurrent()), isolate));
 }
 
 
index ddaea59..4acb1d7 100644 (file)
@@ -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);
       }
index a730b48..d8dff9d 100644 (file)
@@ -459,9 +459,11 @@ void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
         reinterpret_cast<intptr_t>(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()) {
index 6229386..f085622 100644 (file)
@@ -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();
index 018e50f..9dc40f0 100644 (file)
@@ -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<JSObject> 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>(JSObject::cast(holder)));
+    BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())),
+                            Handle<JSObject>(holder));
   }
 
   LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
@@ -7307,14 +7309,19 @@ HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant) {
 
 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
                                                      Handle<JSObject> 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<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
+    iter.Advance();
+    if (iter.IsAtEnd()) {
+      return NULL;
+    }
+  }
+  return BuildConstantMapCheck(
+      Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
 }
 
 
index 7fee8b5..e312a85 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -223,13 +223,13 @@ static void LookupForRead(Handle<Object> object,
       return;
     }
 
-    Handle<Object> 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<JSObject> 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<Code> 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<GlobalObject> global = receiver->IsJSGlobalProxy()
-              ? handle(GlobalObject::cast(receiver->GetPrototype()))
-              : Handle<GlobalObject>::cast(receiver);
+          PrototypeIterator iter(isolate(), receiver);
+          Handle<GlobalObject> global =
+              receiver->IsJSGlobalProxy()
+                  ? Handle<GlobalObject>::cast(
+                        PrototypeIterator::GetCurrent(iter))
+                  : Handle<GlobalObject>::cast(receiver);
           Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
           Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
           StoreGlobalStub stub(
index aa37711..189ea94 100644 (file)
@@ -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();
 }
 
 
index b81921e..b01c49d 100644 (file)
@@ -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<JSGlobalProxy*>(this));
+  return iter.GetCurrent() != global;
 }
 
 
index e6b2e6b..02944df 100644 (file)
@@ -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<void*>(map()) << " ["
      << ElementsKindToString(this->map()->elements_kind())
-     << "]\n - prototype = " << reinterpret_cast<void*>(GetPrototype()) << "\n"
-     << " {\n";
+     << "]\n - prototype = " << reinterpret_cast<void*>(iter.GetCurrent())
+     << "\n {\n";
   PrintProperties(os);
   PrintTransitions(os);
   PrintElements(os);
index 6c60fb3..cead2dd 100644 (file)
@@ -3446,10 +3446,11 @@ void JSObject::LookupOwnRealNamedProperty(Handle<Name> 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<Object> JSObject::SetPropertyForResult(
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return value;
-    ASSERT(proto->IsJSGlobalObject());
-    return SetPropertyForResult(Handle<JSObject>::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<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), lookup,
+        name, value, strict_mode, store_mode);
   }
 
   ASSERT(!lookup->IsFound() || lookup->holder() == *object ||
@@ -4219,12 +4221,12 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return value;
-    ASSERT(proto->IsJSGlobalObject());
-    return SetOwnPropertyIgnoreAttributes(Handle<JSObject>::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<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), name,
+        value, attributes, mode, extensibility_check);
   }
 
   if (lookup.IsInterceptor() ||
@@ -4454,11 +4456,12 @@ PropertyAttributes JSObject::GetElementAttributeWithReceiver(
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> 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<JSObject>::cast(proto), receiver, index, check_prototype);
+        Handle<JSObject>::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<Object> 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<JSProxy>::cast(proto), receiver, index);
+        Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
+        index);
   }
-  if (proto->IsNull()) return ABSENT;
+  if (iter.IsAtEnd()) return ABSENT;
   return GetElementAttributeWithReceiver(
-      Handle<JSObject>::cast(proto), receiver, index, true);
+      Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
+      index, true);
 }
 
 
@@ -5012,11 +5017,11 @@ Object* JSObject::GetHiddenProperty(Handle<Name> 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<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
     // JSGlobalProxies store their hash internally.
     ASSERT(*key != *isolate->factory()->identity_hash_string());
     // For a proxy, use the prototype as target object.
-    Handle<Object> 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<JSObject>::cast(proxy_parent), key, value);
+    if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return SetHiddenProperty(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key,
+        value);
   }
   ASSERT(!object->IsJSGlobalProxy());
 
@@ -5087,10 +5094,11 @@ void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
   ASSERT(key->IsUniqueName());
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return;
-    ASSERT(proto->IsJSGlobalObject());
-    return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key);
+    PrototypeIterator iter(isolate, object);
+    if (iter.IsAtEnd()) return;
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return DeleteHiddenProperty(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key);
   }
 
   Object* inline_value = object->GetHiddenPropertiesHashTable();
@@ -5320,10 +5328,12 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return factory->false_value();
-    ASSERT(proto->IsJSGlobalObject());
-    return DeleteElement(Handle<JSObject>::cast(proto), index, mode);
+    PrototypeIterator iter(isolate, object);
+    if (iter.IsAtEnd()) return factory->false_value();
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return DeleteElement(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
+        mode);
   }
 
   Handle<Object> old_value;
@@ -5375,11 +5385,12 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> 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<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)), name,
+        mode);
   }
 
   uint32_t index = 0;
@@ -5608,10 +5619,11 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return object;
-    ASSERT(proto->IsJSGlobalObject());
-    return PreventExtensions(Handle<JSObject>::cast(proto));
+    PrototypeIterator iter(isolate, object);
+    if (iter.IsAtEnd()) return object;
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return PreventExtensions(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
   }
 
   // It's not possible to seal objects with external array elements
@@ -5691,10 +5703,10 @@ MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return object;
-    ASSERT(proto->IsJSGlobalObject());
-    return Freeze(Handle<JSObject>::cast(proto));
+    PrototypeIterator iter(isolate, object);
+    if (iter.IsAtEnd()) return object;
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return Freeze(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
   }
 
   // It's not possible to freeze objects with external array elements
@@ -6079,12 +6091,11 @@ Handle<Object> JSObject::GetDataProperty(Handle<JSObject> 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> name, LookupResult* result) {
   DisallowHeapAllocation no_gc;
   // Ecma-262 3rd 8.6.2.4
-  Handle<Object> 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<JSObject> object,
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return;
-    ASSERT(proto->IsJSGlobalObject());
-    DefineAccessor(Handle<JSObject>::cast(proto),
-                   name,
-                   getter,
-                   setter,
-                   attributes);
+    PrototypeIterator iter(isolate, object);
+    if (iter.IsAtEnd()) return;
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    DefineAccessor(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
+                   name, getter, setter, attributes);
     return;
   }
 
@@ -6854,10 +6861,11 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return object;
-    ASSERT(proto->IsJSGlobalObject());
-    return SetAccessor(Handle<JSObject>::cast(proto), info);
+    PrototypeIterator iter(isolate, object);
+    if (iter.IsAtEnd()) return object;
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return SetAccessor(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), info);
   }
 
   // Make sure that the top context does not change when doing callbacks or
@@ -6938,11 +6946,14 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
   // Make the lookup and include prototypes.
   uint32_t index = 0;
   if (name->AsArrayIndex(&index)) {
-    for (Handle<Object> 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<Object> JSObject::GetAccessor(Handle<JSObject> object,
       }
     }
   } else {
-    for (Handle<Object> 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<AccessorPair> JSObject::GetOwnElementAccessorPair(
     Handle<JSObject> object,
     uint32_t index) {
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), object->GetIsolate());
-    if (proto->IsNull()) return MaybeHandle<AccessorPair>();
-    ASSERT(proto->IsJSGlobalObject());
-    return GetOwnElementAccessorPair(Handle<JSObject>::cast(proto), index);
+    PrototypeIterator iter(object->GetIsolate(), object);
+    if (iter.IsAtEnd()) return MaybeHandle<AccessorPair>();
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return GetOwnElementAccessorPair(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
   }
 
   // Check for lookup interceptor.
@@ -12811,13 +12824,12 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
   }
 
   if (object->IsJSGlobalProxy()) {
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return value;
-    ASSERT(proto->IsJSGlobalObject());
-    return SetElement(Handle<JSObject>::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<JSObject>::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<Object> JSObject::GetElementWithInterceptor(
       Object);
   if (!result->IsTheHole()) return result;
 
-  Handle<Object> 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<JSObject> object, uint32_t index) {
 
   if (object->IsJSGlobalProxy()) {
     HandleScope scope(isolate);
-    Handle<Object> proto(object->GetPrototype(), isolate);
-    if (proto->IsNull()) return false;
-    ASSERT(proto->IsJSGlobalObject());
-    return HasRealElementProperty(Handle<JSObject>::cast(proto), index);
+    PrototypeIterator iter(isolate, object);
+    if (iter.IsAtEnd()) return false;
+    ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
+    return HasRealElementProperty(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
   }
 
   return GetElementAttributeWithoutInterceptor(
index d33bead..ec6f605 100644 (file)
@@ -1989,9 +1989,6 @@ class JSReceiver: public HeapObject {
       Handle<JSReceiver> 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();
 
index aebdcbc..586df56 100644 (file)
@@ -52,6 +52,11 @@ class PrototypeIterator {
       : did_jump_to_prototype_chain_(true),
         object_(receiver_map->prototype()),
         isolate_(receiver_map->GetIsolate()) {}
+  explicit PrototypeIterator(Handle<Map> 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 {
index 8c3f2ac..17bc34a 100644 (file)
@@ -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>(JSObject::cast(js_object->GetPrototype()));
+      PrototypeIterator iter(isolate, js_object);
+      js_object = Handle<JSObject>::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<Object> proto(object->GetPrototype(), isolate);
-  if (proto->IsJSObject() &&
-      Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
-    return HasOwnPropertyImplementation(isolate,
-                                        Handle<JSObject>::cast(proto),
-                                        key);
+  PrototypeIterator iter(isolate, object);
+  if (!iter.IsAtEnd() &&
+      Handle<JSObject>::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<JSObject>::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>(JSObject::cast(obj->GetPrototype()));
+    PrototypeIterator iter(isolate, obj);
+    obj = Handle<JSObject>::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<int> own_property_count(length);
   int total_property_count = 0;
-  Handle<JSObject> 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>(JSObject::cast(jsproto->GetPrototype()));
+  {
+    PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
+    for (int i = 0; i < length; i++) {
+      ASSERT(!iter.IsAtEnd());
+      Handle<JSObject> jsproto =
+          Handle<JSObject>::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<JSObject> jsproto =
+          Handle<JSObject>::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>(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<Object> 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<JSObject>::cast(proto);
+    if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0);
+    object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
   }
 
   Handle<FixedArray> contents;
@@ -10099,11 +10109,13 @@ static void CollectElementIndices(Handle<JSObject> object,
     }
   }
 
-  Handle<Object> 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<JSObject>::cast(prototype), range, indices);
+    CollectElementIndices(
+        Handle<JSObject>::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<JSObject> jsproto = obj;
+  PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
   for (int i = 0; i < length; i++) {
+    ASSERT(!iter.IsAtEnd());
+    Handle<JSObject> jsproto =
+        Handle<JSObject>::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>(JSObject::cast(jsproto->GetPrototype()));
-    }
+    iter.Advance();
   }
 
   return isolate->heap()->undefined_value();
index 2a3d5c3..0c9f451 100644 (file)
@@ -700,8 +700,9 @@ void StubCompiler::LookupPostInterceptor(Handle<JSObject> 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<Code> 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<JSObject> holder;
     // holder == object indicates that no property was found.
     if (lookup->holder() != *object) {
       holder = Handle<JSObject>(lookup->holder());
     } else {
       // Find the top object.
-      holder = object;
       do {
-        holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
-      } while (holder->GetPrototype()->IsJSObject());
+        holder = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+        iter.Advance();
+      } while (!iter.IsAtEnd());
     }
 
     Register holder_reg = HandlerFrontendHeader(