Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: src/objects.cc

Issue 15504002: Array.observe emit splices for array length change and update index >= length (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: remove todos Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1971 matching lines...) Expand 10 before | Expand all | Expand 10 after
1982 } 1982 }
1983 Handle<Object> args[] = { type, object, name, old_value }; 1983 Handle<Object> args[] = { type, object, name, old_value };
1984 bool threw; 1984 bool threw;
1985 Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()), 1985 Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()),
1986 isolate->factory()->undefined_value(), 1986 isolate->factory()->undefined_value(),
1987 old_value->IsTheHole() ? 3 : 4, args, 1987 old_value->IsTheHole() ? 3 : 4, args,
1988 &threw); 1988 &threw);
1989 ASSERT(!threw); 1989 ASSERT(!threw);
1990 } 1990 }
1991 1991
1992 void JSObject::EnqueueSpliceRecord(Handle<JSObject> object,
1993 uint32_t index,
adamk 2013/05/20 23:13:13 Nit: indentation seems off here.
rafaelw 2013/05/20 23:52:06 Done.
1994 Handle<JSArray> deleted,
1995 uint32_t delete_count,
1996 uint32_t add_count) {
1997 Isolate* isolate = object->GetIsolate();
1998 HandleScope scope(isolate);
1999 if (object->IsJSGlobalObject()) {
adamk 2013/05/20 23:13:13 Can this even happen? Do we ever emit splices for
rafaelw 2013/05/20 23:52:06 Replaced with assert. On 2013/05/20 23:13:13, ada
adamk 2013/05/21 19:11:11 Now that you've added the assert I'm wondering wha
rafaelw 2013/05/23 18:19:58 These only get called from within objects.cc, but
2000 object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate);
2001 }
2002
2003 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
2004 Handle<Object> delete_count_object =
adamk 2013/05/20 23:13:13 It's not obvious why we need the delete_count here
rafaelw 2013/05/20 23:52:06 You are correct. This is an artifact of having spl
2005 isolate->factory()->NewNumberFromUint(delete_count);
2006 Handle<Object> add_count_object =
2007 isolate->factory()->NewNumberFromUint(add_count);
2008
2009 Handle<Object> args[] =
2010 { object, index_object, deleted, delete_count_object, add_count_object };
2011
2012 bool threw;
2013 Execution::Call(Handle<JSFunction>(isolate->observers_enqueue_splice()),
2014 isolate->factory()->undefined_value(), 5, args,
2015 &threw);
2016 ASSERT(!threw);
2017 }
2018
2019 void JSObject::BeginPerformSplice(Handle<JSObject> object) {
2020 Isolate* isolate = object->GetIsolate();
2021 HandleScope scope(isolate);
2022 if (object->IsJSGlobalObject()) {
adamk 2013/05/20 23:13:13 Same question as above, can this happen?
rafaelw 2013/05/20 23:52:06 Done.
2023 object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate);
2024 }
2025
2026 Handle<Object> args[] = { object };
2027
2028 bool threw;
2029 Execution::Call(Handle<JSFunction>(isolate->observers_begin_perform_splice()),
2030 isolate->factory()->undefined_value(), 1, args,
2031 &threw);
2032 ASSERT(!threw);
2033 }
2034
2035 void JSObject::EndPerformSplice(Handle<JSObject> object) {
2036 Isolate* isolate = object->GetIsolate();
2037 HandleScope scope(isolate);
2038 if (object->IsJSGlobalObject()) {
adamk 2013/05/20 23:13:13 ditto
rafaelw 2013/05/20 23:52:06 Done.
2039 object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate);
2040 }
2041
2042 Handle<Object> args[] = { object };
2043
2044 bool threw;
2045 Execution::Call(Handle<JSFunction>(isolate->observers_end_perform_splice()),
2046 isolate->factory()->undefined_value(), 1, args,
2047 &threw);
2048 ASSERT(!threw);
2049 }
1992 2050
1993 void JSObject::DeliverChangeRecords(Isolate* isolate) { 2051 void JSObject::DeliverChangeRecords(Isolate* isolate) {
1994 ASSERT(isolate->observer_delivery_pending()); 2052 ASSERT(isolate->observer_delivery_pending());
1995 bool threw = false; 2053 bool threw = false;
1996 Execution::Call( 2054 Execution::Call(
1997 isolate->observers_deliver_changes(), 2055 isolate->observers_deliver_changes(),
1998 isolate->factory()->undefined_value(), 2056 isolate->factory()->undefined_value(),
1999 0, 2057 0,
2000 NULL, 2058 NULL,
2001 &threw); 2059 &threw);
(...skipping 8720 matching lines...) Expand 10 before | Expand all | Expand 10 after
10722 MaybeObject* JSArray::SetElementsLength(Object* len) { 10780 MaybeObject* JSArray::SetElementsLength(Object* len) {
10723 // We should never end in here with a pixel or external array. 10781 // We should never end in here with a pixel or external array.
10724 ASSERT(AllowsSetElementsLength()); 10782 ASSERT(AllowsSetElementsLength());
10725 if (!(FLAG_harmony_observation && map()->is_observed())) 10783 if (!(FLAG_harmony_observation && map()->is_observed()))
10726 return GetElementsAccessor()->SetLength(this, len); 10784 return GetElementsAccessor()->SetLength(this, len);
10727 10785
10728 Isolate* isolate = GetIsolate(); 10786 Isolate* isolate = GetIsolate();
10729 HandleScope scope(isolate); 10787 HandleScope scope(isolate);
10730 Handle<JSArray> self(this); 10788 Handle<JSArray> self(this);
10731 List<Handle<String> > indices; 10789 List<Handle<String> > indices;
10790 List<uint32_t> int_indices;
10732 List<Handle<Object> > old_values; 10791 List<Handle<Object> > old_values;
10733 Handle<Object> old_length_handle(self->length(), isolate); 10792 Handle<Object> old_length_handle(self->length(), isolate);
10734 Handle<Object> new_length_handle(len, isolate); 10793 Handle<Object> new_length_handle(len, isolate);
10735 uint32_t old_length = 0; 10794 uint32_t old_length = 0;
10736 CHECK(old_length_handle->ToArrayIndex(&old_length)); 10795 CHECK(old_length_handle->ToArrayIndex(&old_length));
10737 uint32_t new_length = 0; 10796 uint32_t new_length = 0;
10738 if (!new_length_handle->ToArrayIndex(&new_length)) 10797 if (!new_length_handle->ToArrayIndex(&new_length))
10739 return Failure::InternalError(); 10798 return Failure::InternalError();
10740 10799
10741 // Observed arrays should always be in dictionary mode; 10800 // Observed arrays should always be in dictionary mode;
10742 // if they were in fast mode, the below is slower than necessary 10801 // if they were in fast mode, the below is slower than necessary
10743 // as it iterates over the array backing store multiple times. 10802 // as it iterates over the array backing store multiple times.
10744 ASSERT(self->HasDictionaryElements()); 10803 ASSERT(self->HasDictionaryElements());
10745 static const PropertyAttributes kNoAttrFilter = NONE; 10804 static const PropertyAttributes kNoAttrFilter = NONE;
10746 int num_elements = self->NumberOfLocalElements(kNoAttrFilter); 10805 int num_elements = self->NumberOfLocalElements(kNoAttrFilter);
10747 if (num_elements > 0) { 10806 if (num_elements > 0) {
10748 if (old_length == static_cast<uint32_t>(num_elements)) { 10807 if (old_length == static_cast<uint32_t>(num_elements)) {
10749 // Simple case for arrays without holes. 10808 // Simple case for arrays without holes.
10750 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { 10809 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
10751 if (!GetOldValue(isolate, self, i, &old_values, &indices)) break; 10810 if (!GetOldValue(isolate, self, i, &old_values, &indices)) break;
10811 int_indices.Add(i);
adamk 2013/05/20 23:13:13 It seems odd to keep track of the indices twice. A
rafaelw 2013/05/20 23:52:06 Done.
10752 } 10812 }
10753 } else { 10813 } else {
10754 // For sparse arrays, only iterate over existing elements. 10814 // For sparse arrays, only iterate over existing elements.
10755 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements); 10815 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
10756 self->GetLocalElementKeys(*keys, kNoAttrFilter); 10816 self->GetLocalElementKeys(*keys, kNoAttrFilter);
10757 while (num_elements-- > 0) { 10817 while (num_elements-- > 0) {
10758 uint32_t index = NumberToUint32(keys->get(num_elements)); 10818 uint32_t index = NumberToUint32(keys->get(num_elements));
10759 if (index < new_length) break; 10819 if (index < new_length) break;
10760 if (!GetOldValue(isolate, self, index, &old_values, &indices)) break; 10820 if (!GetOldValue(isolate, self, index, &old_values, &indices)) break;
10821 int_indices.Add(index);
10761 } 10822 }
10762 } 10823 }
10763 } 10824 }
10764 10825
10765 MaybeObject* result = 10826 MaybeObject* result =
10766 self->GetElementsAccessor()->SetLength(*self, *new_length_handle); 10827 self->GetElementsAccessor()->SetLength(*self, *new_length_handle);
10767 Handle<Object> hresult; 10828 Handle<Object> hresult;
10768 if (!result->ToHandle(&hresult, isolate)) return result; 10829 if (!result->ToHandle(&hresult, isolate)) return result;
10769 10830
10770 CHECK(self->length()->ToArrayIndex(&new_length)); 10831 CHECK(self->length()->ToArrayIndex(&new_length));
10771 if (old_length != new_length) { 10832 if (old_length == new_length)
10772 for (int i = 0; i < indices.length(); ++i) { 10833 return *hresult;
10773 JSObject::EnqueueChangeRecord( 10834
10774 self, "deleted", indices[i], old_values[i]); 10835 JSObject::BeginPerformSplice(self);
10775 } 10836
10837 for (int i = 0; i < indices.length(); ++i) {
10776 JSObject::EnqueueChangeRecord( 10838 JSObject::EnqueueChangeRecord(
10777 self, "updated", isolate->factory()->length_string(), 10839 self, "deleted", indices[i], old_values[i]);
10778 old_length_handle);
10779 } 10840 }
10841 JSObject::EnqueueChangeRecord(
10842 self, "updated", isolate->factory()->length_string(),
10843 old_length_handle);
10844
10845 JSObject::EndPerformSplice(self);
10846
10847 uint32_t index = new_length > old_length ? old_length : new_length;
10848 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
10849 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
10850 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
10851 if (delete_count) {
10852 for (int i = 0; i < int_indices.length(); ++i)
10853 JSObject::SetElement(deleted, int_indices[i] - index, old_values[i],
10854 NONE, kNonStrictMode);
10855 }
10856
10857 JSObject::EnqueueSpliceRecord(self, index, deleted, delete_count, add_count);
10858
10780 return *hresult; 10859 return *hresult;
10781 } 10860 }
10782 10861
10783 10862
10784 Map* Map::GetPrototypeTransition(Object* prototype) { 10863 Map* Map::GetPrototypeTransition(Object* prototype) {
10785 FixedArray* cache = GetPrototypeTransitions(); 10864 FixedArray* cache = GetPrototypeTransitions();
10786 int number_of_transitions = NumberOfProtoTransitions(); 10865 int number_of_transitions = NumberOfProtoTransitions();
10787 const int proto_offset = 10866 const int proto_offset =
10788 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset; 10867 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
10789 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; 10868 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
(...skipping 1005 matching lines...) Expand 10 before | Expand all | Expand 10 after
11795 index, value_raw, attributes, strict_mode, check_prototype, set_mode) 11874 index, value_raw, attributes, strict_mode, check_prototype, set_mode)
11796 : SetElementWithoutInterceptor( 11875 : SetElementWithoutInterceptor(
11797 index, value_raw, attributes, strict_mode, check_prototype, set_mode); 11876 index, value_raw, attributes, strict_mode, check_prototype, set_mode);
11798 } 11877 }
11799 11878
11800 // From here on, everything has to be handlified. 11879 // From here on, everything has to be handlified.
11801 Handle<JSObject> self(this); 11880 Handle<JSObject> self(this);
11802 Handle<Object> value(value_raw, isolate); 11881 Handle<Object> value(value_raw, isolate);
11803 PropertyAttributes old_attributes = self->GetLocalElementAttribute(index); 11882 PropertyAttributes old_attributes = self->GetLocalElementAttribute(index);
11804 Handle<Object> old_value = isolate->factory()->the_hole_value(); 11883 Handle<Object> old_value = isolate->factory()->the_hole_value();
11805 Handle<Object> old_length; 11884 Handle<Object> old_length_handle;
11885 Handle<Object> new_length_handle;
11886 uint32_t old_length = 0;
11887 uint32_t new_length = 0;
11806 11888
11807 if (old_attributes != ABSENT) { 11889 if (old_attributes != ABSENT) {
11808 if (self->GetLocalElementAccessorPair(index) == NULL) 11890 if (self->GetLocalElementAccessorPair(index) == NULL)
11809 old_value = Object::GetElement(self, index); 11891 old_value = Object::GetElement(self, index);
11810 } else if (self->IsJSArray()) { 11892 } else if (self->IsJSArray()) {
11811 // Store old array length in case adding an element grows the array. 11893 // Store old array length in case adding an element grows the array.
11812 old_length = handle(Handle<JSArray>::cast(self)->length(), isolate); 11894 old_length_handle = handle(Handle<JSArray>::cast(self)->length(), isolate);
11895 CHECK(old_length_handle->ToArrayIndex(&old_length));
11813 } 11896 }
11814 11897
11815 // Check for lookup interceptor 11898 // Check for lookup interceptor
11816 MaybeObject* result = self->HasIndexedInterceptor() 11899 MaybeObject* result = self->HasIndexedInterceptor()
11817 ? self->SetElementWithInterceptor( 11900 ? self->SetElementWithInterceptor(
11818 index, *value, attributes, strict_mode, check_prototype, set_mode) 11901 index, *value, attributes, strict_mode, check_prototype, set_mode)
11819 : self->SetElementWithoutInterceptor( 11902 : self->SetElementWithoutInterceptor(
11820 index, *value, attributes, strict_mode, check_prototype, set_mode); 11903 index, *value, attributes, strict_mode, check_prototype, set_mode);
11821 11904
11822 Handle<Object> hresult; 11905 Handle<Object> hresult;
11823 if (!result->ToHandle(&hresult, isolate)) return result; 11906 if (!result->ToHandle(&hresult, isolate)) return result;
11824 11907
11825 Handle<String> name = isolate->factory()->Uint32ToString(index); 11908 Handle<String> name = isolate->factory()->Uint32ToString(index);
11826 PropertyAttributes new_attributes = self->GetLocalElementAttribute(index); 11909 PropertyAttributes new_attributes = self->GetLocalElementAttribute(index);
11827 if (old_attributes == ABSENT) { 11910 if (old_attributes == ABSENT) {
11911 bool array_extended = false;
11912 if (self->IsJSArray() &&
11913 !old_length_handle->SameValue(Handle<JSArray>::cast(self)->length())) {
11914 array_extended = true;
11915 new_length_handle = handle(Handle<JSArray>::cast(self)->length(),
11916 isolate);
11917 CHECK(new_length_handle->ToArrayIndex(&new_length));
11918 JSObject::BeginPerformSplice(self);
11919 }
11920
11828 EnqueueChangeRecord(self, "new", name, old_value); 11921 EnqueueChangeRecord(self, "new", name, old_value);
11829 if (self->IsJSArray() && 11922 if (array_extended) {
11830 !old_length->SameValue(Handle<JSArray>::cast(self)->length())) { 11923 EnqueueChangeRecord(self, "updated", isolate->factory()->length_string(),
11831 EnqueueChangeRecord( 11924 old_length_handle);
11832 self, "updated", isolate->factory()->length_string(), old_length); 11925
11926 JSObject::EndPerformSplice(self);
11927 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
11928 JSObject::EnqueueSpliceRecord(self, old_length, deleted, 0,
11929 new_length - old_length);
11833 } 11930 }
11834 } else if (old_value->IsTheHole()) { 11931 } else if (old_value->IsTheHole()) {
11835 EnqueueChangeRecord(self, "reconfigured", name, old_value); 11932 EnqueueChangeRecord(self, "reconfigured", name, old_value);
11836 } else { 11933 } else {
11837 Handle<Object> new_value = Object::GetElement(self, index); 11934 Handle<Object> new_value = Object::GetElement(self, index);
11838 bool value_changed = !old_value->SameValue(*new_value); 11935 bool value_changed = !old_value->SameValue(*new_value);
11839 if (old_attributes != new_attributes) { 11936 if (old_attributes != new_attributes) {
11840 if (!value_changed) old_value = isolate->factory()->the_hole_value(); 11937 if (!value_changed) old_value = isolate->factory()->the_hole_value();
11841 EnqueueChangeRecord(self, "reconfigured", name, old_value); 11938 EnqueueChangeRecord(self, "reconfigured", name, old_value);
11842 } else if (value_changed) { 11939 } else if (value_changed) {
(...skipping 3594 matching lines...) Expand 10 before | Expand all | Expand 10 after
15437 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 15534 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
15438 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 15535 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
15439 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 15536 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
15440 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 15537 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
15441 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 15538 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
15442 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 15539 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
15443 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 15540 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
15444 } 15541 }
15445 15542
15446 } } // namespace v8::internal 15543 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/v8natives.js » ('j') | test/mjsunit/harmony/object-observe.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698