Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 702d8a222dcdd8ee31d06fec4206eaf3d6445c33..1571d79c48ff0b7ade03214983088bfbe047f31c 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -28,6 +28,7 @@ |
#include "src/mark-compact.h" |
#include "src/objects-inl.h" |
#include "src/objects-visiting-inl.h" |
+#include "src/prototype.h" |
#include "src/safepoint-table.h" |
#include "src/string-search.h" |
#include "src/string-stream.h" |
@@ -801,30 +802,30 @@ MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, |
Handle<Object> object, |
Handle<Object> receiver, |
uint32_t index) { |
- Handle<Object> holder; |
+ if (object->IsUndefined()) { |
+ // TODO(verwaest): Why is this check here? |
+ UNREACHABLE(); |
+ return isolate->factory()->undefined_value(); |
+ } |
// Iterate up the prototype chain until an element is found or the null |
// prototype is encountered. |
- for (holder = object; |
- !holder->IsNull(); |
- holder = Handle<Object>(holder->GetPrototype(isolate), isolate)) { |
- if (!holder->IsJSObject()) { |
- if (holder->IsJSProxy()) { |
- return JSProxy::GetElementWithHandler( |
- Handle<JSProxy>::cast(holder), receiver, index); |
- } else if (holder->IsUndefined()) { |
- // Undefined has no indexed properties. |
- return isolate->factory()->undefined_value(); |
- } else { |
- holder = Handle<Object>(holder->GetPrototype(isolate), isolate); |
- ASSERT(holder->IsJSObject()); |
- } |
+ for (PrototypeIterator iter(isolate, object, |
+ object->IsJSProxy() || object->IsJSObject() |
+ ? PrototypeIterator::START_AT_RECEIVER |
+ : PrototypeIterator::START_AT_PROTOTYPE); |
+ !iter.IsAtEnd(); iter.Advance()) { |
+ if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
+ return JSProxy::GetElementWithHandler( |
+ Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver, |
+ index); |
} |
// Inline the case for JSObjects. Doing so significantly improves the |
// performance of fetching elements where checking the prototype chain is |
// necessary. |
- Handle<JSObject> js_object = Handle<JSObject>::cast(holder); |
+ Handle<JSObject> js_object = |
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
// Check access rights if needed. |
if (js_object->IsAccessCheckNeeded()) { |
@@ -853,11 +854,11 @@ MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, |
} |
-Object* Object::GetPrototype(Isolate* isolate) { |
+Map* Object::GetRootMap(Isolate* isolate) { |
DisallowHeapAllocation no_alloc; |
if (IsSmi()) { |
Context* context = isolate->context()->native_context(); |
- return context->number_function()->instance_prototype(); |
+ return context->number_function()->initial_map(); |
} |
HeapObject* heap_object = HeapObject::cast(this); |
@@ -865,30 +866,23 @@ Object* Object::GetPrototype(Isolate* isolate) { |
// The object is either a number, a string, a boolean, |
// a real JS object, or a Harmony proxy. |
if (heap_object->IsJSReceiver()) { |
- return heap_object->map()->prototype(); |
+ return heap_object->map(); |
} |
Context* context = isolate->context()->native_context(); |
if (heap_object->IsHeapNumber()) { |
- return context->number_function()->instance_prototype(); |
+ return context->number_function()->initial_map(); |
} |
if (heap_object->IsString()) { |
- return context->string_function()->instance_prototype(); |
+ return context->string_function()->initial_map(); |
} |
if (heap_object->IsSymbol()) { |
- return context->symbol_function()->instance_prototype(); |
+ return context->symbol_function()->initial_map(); |
} |
if (heap_object->IsBoolean()) { |
- return context->boolean_function()->instance_prototype(); |
- } else { |
- return isolate->heap()->null_value(); |
+ return context->boolean_function()->initial_map(); |
} |
-} |
- |
- |
-Handle<Object> Object::GetPrototype(Isolate* isolate, |
- Handle<Object> object) { |
- return handle(object->GetPrototype(isolate), isolate); |
+ return isolate->heap()->null_value()->map(); |
} |
@@ -3028,20 +3022,16 @@ MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes( |
bool* found, |
StrictMode strict_mode) { |
Isolate *isolate = object->GetIsolate(); |
- for (Handle<Object> proto = handle(object->GetPrototype(), isolate); |
- !proto->IsNull(); |
- proto = handle(proto->GetPrototype(isolate), isolate)) { |
- if (proto->IsJSProxy()) { |
+ for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd(); |
+ iter.Advance()) { |
+ if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
return JSProxy::SetPropertyViaPrototypesWithHandler( |
- Handle<JSProxy>::cast(proto), |
- object, |
+ Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), object, |
isolate->factory()->Uint32ToString(index), // name |
- value, |
- NONE, |
- strict_mode, |
- found); |
+ value, NONE, strict_mode, found); |
} |
- Handle<JSObject> js_proto = Handle<JSObject>::cast(proto); |
+ Handle<JSObject> js_proto = |
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
if (!js_proto->HasDictionaryElements()) { |
continue; |
} |
@@ -3519,14 +3509,11 @@ void JSObject::LookupRealNamedPropertyInPrototypes(Handle<Name> name, |
LookupResult* result) { |
DisallowHeapAllocation no_gc; |
Isolate* isolate = GetIsolate(); |
- Heap* heap = isolate->heap(); |
- for (Object* pt = GetPrototype(); |
- pt != heap->null_value(); |
- pt = pt->GetPrototype(isolate)) { |
- if (pt->IsJSProxy()) { |
- return result->HandlerResult(JSProxy::cast(pt)); |
+ for (PrototypeIterator iter(isolate, this); !iter.IsAtEnd(); iter.Advance()) { |
+ if (iter.GetCurrent()->IsJSProxy()) { |
+ return result->HandlerResult(JSProxy::cast(iter.GetCurrent())); |
} |
- JSObject::cast(pt)->LookupOwnRealNamedProperty(name, result); |
+ JSObject::cast(iter.GetCurrent())->LookupOwnRealNamedProperty(name, result); |
ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR)); |
if (result->IsFound()) return; |
} |
@@ -6369,11 +6356,12 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
JSFunction::cast(isolate->sloppy_arguments_map()->constructor())); |
// Only collect keys if access is permitted. |
- for (Handle<Object> p = object; |
- *p != isolate->heap()->null_value(); |
- p = Handle<Object>(p->GetPrototype(isolate), isolate)) { |
- if (p->IsJSProxy()) { |
- Handle<JSProxy> proxy(JSProxy::cast(*p), isolate); |
+ for (PrototypeIterator iter(isolate, object, |
+ PrototypeIterator::START_AT_RECEIVER); |
+ !iter.IsAtEnd(); iter.Advance()) { |
+ if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
+ Handle<JSProxy> proxy(JSProxy::cast(*PrototypeIterator::GetCurrent(iter)), |
+ isolate); |
Handle<Object> args[] = { proxy }; |
Handle<Object> names; |
ASSIGN_RETURN_ON_EXCEPTION( |
@@ -6392,7 +6380,8 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object, |
break; |
} |
- Handle<JSObject> current(JSObject::cast(*p), isolate); |
+ Handle<JSObject> current = |
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
// Check access rights if required. |
if (current->IsAccessCheckNeeded() && |
@@ -6610,22 +6599,18 @@ void JSObject::DefinePropertyAccessor(Handle<JSObject> object, |
bool Map::DictionaryElementsInPrototypeChainOnly() { |
- Heap* heap = GetHeap(); |
- |
if (IsDictionaryElementsKind(elements_kind())) { |
return false; |
} |
- for (Object* prototype = this->prototype(); |
- prototype != heap->null_value(); |
- prototype = prototype->GetPrototype(GetIsolate())) { |
- if (prototype->IsJSProxy()) { |
+ for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) { |
+ if (iter.GetCurrent()->IsJSProxy()) { |
// Be conservative, don't walk into proxies. |
return true; |
} |
if (IsDictionaryElementsKind( |
- JSObject::cast(prototype)->map()->elements_kind())) { |
+ JSObject::cast(iter.GetCurrent())->map()->elements_kind())) { |
return true; |
} |
} |
@@ -10126,9 +10111,14 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { |
Handle<Object> prototype; |
if (function->has_instance_prototype()) { |
prototype = handle(function->instance_prototype(), isolate); |
- for (Handle<Object> p = prototype; !p->IsNull() && !p->IsJSProxy(); |
- p = Object::GetPrototype(isolate, p)) { |
- JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(p)); |
+ for (PrototypeIterator iter(isolate, prototype, |
+ PrototypeIterator::START_AT_RECEIVER); |
+ !iter.IsAtEnd(); iter.Advance()) { |
+ if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
+ break; |
+ } |
+ JSObject::OptimizeAsPrototype( |
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))); |
} |
} else { |
prototype = isolate->factory()->NewFunctionPrototype(function); |
@@ -12198,10 +12188,10 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
// prototype cycles are prevented. |
// It is sufficient to validate that the receiver is not in the new prototype |
// chain. |
- for (Object* pt = *value; |
- pt != heap->null_value(); |
- pt = pt->GetPrototype(isolate)) { |
- if (JSReceiver::cast(pt) == *object) { |
+ for (PrototypeIterator iter(isolate, *value, |
+ PrototypeIterator::START_AT_RECEIVER); |
+ !iter.IsAtEnd(); iter.Advance()) { |
+ if (JSReceiver::cast(iter.GetCurrent()) == *object) { |
// Cycle detected. |
Handle<Object> error = isolate->factory()->NewError( |
"cyclic_proto", HandleVector<Object>(NULL, 0)); |
@@ -12216,11 +12206,11 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
if (skip_hidden_prototypes) { |
// Find the first object in the chain whose prototype object is not |
// hidden and set the new prototype on that object. |
- Object* current_proto = real_receiver->GetPrototype(); |
- while (current_proto->IsJSObject() && |
- JSObject::cast(current_proto)->map()->is_hidden_prototype()) { |
- real_receiver = handle(JSObject::cast(current_proto), isolate); |
- current_proto = current_proto->GetPrototype(isolate); |
+ PrototypeIterator iter(isolate, real_receiver); |
+ while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
+ real_receiver = |
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
+ iter.Advance(); |
} |
} |