Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index bc4a63cc02e2c43b24e23a2aac5a1ae99cebfd45..8ba7044e300baac558bb7e87dd4282216de7487d 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -3302,8 +3302,7 @@ PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { |
// Check whether the name is an array index. |
uint32_t index = 0; |
if (IsJSObject() && name->AsArrayIndex(&index)) { |
- if (JSObject::cast(this)->HasLocalElement(index)) return NONE; |
- return ABSENT; |
+ return GetLocalElementAttribute(index); |
} |
// Named property. |
LookupResult lookup(GetIsolate()); |
@@ -3312,6 +3311,27 @@ PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { |
} |
+PropertyAttributes JSObject::GetLocalElementAttribute(uint32_t index) { |
+ // Check access rights if needed. |
+ if (IsAccessCheckNeeded()) { |
+ Heap* heap = GetHeap(); |
+ if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
+ return ABSENT; |
+ } |
+ } |
+ |
+ if (IsJSGlobalProxy()) { |
+ Object* proto = GetPrototype(); |
+ if (proto->IsNull()) return ABSENT; |
+ ASSERT(proto->IsJSGlobalObject()); |
+ return JSReceiver::cast(proto)->GetLocalElementAttribute(index); |
+ } |
+ |
+ return GetElementsAccessor()->GetAttributes(this, this, index); |
+} |
+ |
+ |
MaybeObject* NormalizedMapCache::Get(JSObject* obj, |
PropertyNormalizationMode mode) { |
Isolate* isolate = obj->GetIsolate(); |
@@ -4033,15 +4053,43 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { |
return JSGlobalObject::cast(proto)->DeleteElement(index, mode); |
} |
- if (HasIndexedInterceptor()) { |
- // Skip interceptor if forcing deletion. |
- if (mode != FORCE_DELETION) { |
- return DeleteElementWithInterceptor(index); |
+ // From this point on everything needs to be handlified. |
+ HandleScope scope(isolate); |
+ Handle<JSObject> self(this); |
+ |
+ Handle<String> name; |
+ Handle<Object> old_value(isolate->heap()->the_hole_value()); |
+ bool preexists = false; |
+ if (FLAG_harmony_observation && map()->is_observed()) { |
+ name = isolate->factory()->Uint32ToString(index); |
+ preexists = self->HasLocalElement(index); |
+ if (preexists) { |
+ // TODO(observe): only read & set old_value if it's not an accessor |
+ old_value = Object::GetElement(self, index); |
} |
- mode = JSReceiver::FORCE_DELETION; |
} |
- return GetElementsAccessor()->Delete(this, index, mode); |
+ MaybeObject* result; |
+ // Skip interceptor if forcing deletion. |
+ if (self->HasIndexedInterceptor()) { |
Toon Verwaest
2012/11/07 10:06:52
Maybe use (self->HasIndexedInterceptor() && mode !
rossberg
2012/11/07 18:41:42
Done.
|
+ if (mode != FORCE_DELETION) |
+ result = self->DeleteElementWithInterceptor(index); |
+ else |
+ result = self->GetElementsAccessor()->Delete( |
+ *self, index, JSReceiver::FORCE_DELETION); |
+ } else { |
+ result = self->GetElementsAccessor()->Delete(*self, index, mode); |
+ } |
+ |
+ Handle<Object> hresult; |
+ if (!result->ToHandle(&hresult)) return result; |
+ |
+ if (FLAG_harmony_observation && map()->is_observed()) { |
+ if (preexists && !self->HasLocalElement(index)) |
+ self->EnqueueChangeRecord("deleted", name, old_value); |
+ } |
+ |
+ return *hresult; |
} |
@@ -10114,28 +10162,31 @@ Handle<Object> JSObject::SetElement(Handle<JSObject> object, |
MaybeObject* JSObject::SetElement(uint32_t index, |
- Object* value, |
+ Object* value_raw, |
PropertyAttributes attributes, |
StrictModeFlag strict_mode, |
bool check_prototype, |
SetPropertyMode set_mode) { |
+ Isolate* isolate = GetIsolate(); |
+ HandleScope scope(isolate); |
+ Handle<JSObject> self(this); |
+ Handle<Object> value(value_raw); |
+ |
// Check access rights if needed. |
if (IsAccessCheckNeeded()) { |
Heap* heap = GetHeap(); |
- if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { |
- HandleScope scope(heap->isolate()); |
- Handle<Object> value_handle(value); |
- heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
- return *value_handle; |
+ if (!heap->isolate()->MayIndexedAccess(*self, index, v8::ACCESS_SET)) { |
+ heap->isolate()->ReportFailedAccessCheck(*self, v8::ACCESS_SET); |
+ return *value; |
} |
} |
if (IsJSGlobalProxy()) { |
Object* proto = GetPrototype(); |
- if (proto->IsNull()) return value; |
+ if (proto->IsNull()) return *value; |
ASSERT(proto->IsJSGlobalObject()); |
return JSObject::cast(proto)->SetElement(index, |
- value, |
+ *value, |
attributes, |
strict_mode, |
check_prototype, |
@@ -10144,10 +10195,8 @@ MaybeObject* JSObject::SetElement(uint32_t index, |
// Don't allow element properties to be redefined for external arrays. |
if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) { |
- Isolate* isolate = GetHeap()->isolate(); |
- Handle<Object> receiver(this); |
Handle<Object> number = isolate->factory()->NewNumberFromUint(index); |
- Handle<Object> args[] = { receiver, number }; |
+ Handle<Object> args[] = { self, number }; |
Handle<Object> error = isolate->factory()->NewTypeError( |
"redef_external_array_element", HandleVector(args, ARRAY_SIZE(args))); |
return isolate->Throw(*error); |
@@ -10162,22 +10211,56 @@ MaybeObject* JSObject::SetElement(uint32_t index, |
dictionary->set_requires_slow_elements(); |
} |
+ // From here on, everything has to be handlified. |
+ Handle<String> name; |
+ Handle<Object> old_value(isolate->heap()->the_hole_value()); |
+ PropertyAttributes old_attributes; |
+ bool preexists = false; |
+ if (FLAG_harmony_observation && map()->is_observed()) { |
+ name = isolate->factory()->Uint32ToString(index); |
+ preexists = self->HasLocalElement(index); |
+ if (preexists) { |
+ old_attributes = self->GetLocalPropertyAttribute(*name); |
+ // TODO(observe): only read & set old_value if we have a data property |
+ old_value = Object::GetElement(self, index); |
+ } |
+ } |
+ |
// Check for lookup interceptor |
- if (HasIndexedInterceptor()) { |
- return SetElementWithInterceptor(index, |
- value, |
- attributes, |
- strict_mode, |
- check_prototype, |
- set_mode); |
+ MaybeObject* result = *value; |
Toon Verwaest
2012/11/07 10:06:52
This initialization seems superfluous since it's o
rossberg
2012/11/07 18:41:42
Done.
|
+ if (self->HasIndexedInterceptor()) { |
+ result = self->SetElementWithInterceptor(index, |
+ *value, |
+ attributes, |
+ strict_mode, |
+ check_prototype, |
+ set_mode); |
+ } else { |
+ result = self->SetElementWithoutInterceptor(index, |
+ *value, |
+ attributes, |
+ strict_mode, |
+ check_prototype, |
+ set_mode); |
} |
- return SetElementWithoutInterceptor(index, |
- value, |
- attributes, |
- strict_mode, |
- check_prototype, |
- set_mode); |
+ Handle<Object> hresult; |
+ if (!result->ToHandle(&hresult)) return result; |
+ |
+ if (FLAG_harmony_observation && map()->is_observed()) { |
+ PropertyAttributes new_attributes = self->GetLocalPropertyAttribute(*name); |
+ if (!preexists) { |
+ self->EnqueueChangeRecord("new", name, old_value); |
+ } else if (new_attributes != old_attributes || old_value->IsTheHole()) { |
+ self->EnqueueChangeRecord("reconfigured", name, old_value); |
+ } else { |
+ Handle<Object> newValue = Object::GetElement(self, index); |
+ if (!newValue->SameValue(*old_value)) |
+ self->EnqueueChangeRecord("updated", name, old_value); |
+ } |
+ } |
+ |
+ return *hresult; |
} |