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);
}
"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));
}
// 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();
}
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);
}
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);
}
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()) {
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();
// 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);
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)));
}
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);
}
}
// 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
// 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(
// 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();
}
#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"
}
-Object* JSReceiver::GetPrototype() const {
- return map()->prototype();
-}
-
-
Object* JSReceiver::GetConstructor() {
return map()->constructor();
}
bool JSGlobalProxy::IsDetachedFrom(GlobalObject* global) const {
- return GetPrototype() != global;
+ const PrototypeIterator iter(this->GetIsolate(),
+ const_cast<JSGlobalProxy*>(this));
+ return iter.GetCurrent() != global;
}
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);
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()) {
}
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 ||
}
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() ||
}
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.
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);
}
// 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();
// 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());
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();
}
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;
}
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;
}
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
}
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
// - 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;
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()) {
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);
}
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();
}
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;
}
}
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
// 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) {
}
}
} 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()) {
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.
}
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.
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);
}
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(
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();
: 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 {
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());
}
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() ||
// 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();
// 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;
}
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.
// 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();
}
}
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();
}
}
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;
}
}
- 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);
}
}
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()) {
return *isolate->factory()->NewJSArrayWithElements(details);
}
- if (i < length - 1) {
- jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
- }
+ iter.Advance();
}
return isolate->heap()->undefined_value();
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);
}
__ 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(