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

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: whitespace 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 10881 matching lines...) Expand 10 before | Expand all | Expand 10 after
10892 } 10892 }
10893 10893
10894 10894
10895 // Returns false if the passed-in index is marked non-configurable, 10895 // Returns false if the passed-in index is marked non-configurable,
10896 // which will cause the ES5 truncation operation to halt, and thus 10896 // which will cause the ES5 truncation operation to halt, and thus
10897 // no further old values need be collected. 10897 // no further old values need be collected.
10898 static bool GetOldValue(Isolate* isolate, 10898 static bool GetOldValue(Isolate* isolate,
10899 Handle<JSObject> object, 10899 Handle<JSObject> object,
10900 uint32_t index, 10900 uint32_t index,
10901 List<Handle<Object> >* old_values, 10901 List<Handle<Object> >* old_values,
10902 List<Handle<String> >* indices) { 10902 List<uint32_t>* indices) {
10903 PropertyAttributes attributes = object->GetLocalElementAttribute(index); 10903 PropertyAttributes attributes = object->GetLocalElementAttribute(index);
10904 ASSERT(attributes != ABSENT); 10904 ASSERT(attributes != ABSENT);
10905 if (attributes == DONT_DELETE) return false; 10905 if (attributes == DONT_DELETE) return false;
10906 old_values->Add(object->GetLocalElementAccessorPair(index) == NULL 10906 old_values->Add(object->GetLocalElementAccessorPair(index) == NULL
10907 ? Object::GetElement(object, index) 10907 ? Object::GetElement(object, index)
10908 : Handle<Object>::cast(isolate->factory()->the_hole_value())); 10908 : Handle<Object>::cast(isolate->factory()->the_hole_value()));
10909 indices->Add(isolate->factory()->Uint32ToString(index)); 10909 indices->Add(index);
10910 return true; 10910 return true;
10911 } 10911 }
10912 10912
10913 10913
10914 // TODO(rafaelw): Remove |delete_count| argument and rely on the length of
10915 // of |deleted|.
10916 static void EnqueueSpliceRecord(Handle<JSArray> object,
10917 uint32_t index,
10918 Handle<JSArray> deleted,
10919 uint32_t delete_count,
10920 uint32_t add_count) {
10921 Isolate* isolate = object->GetIsolate();
10922 HandleScope scope(isolate);
10923 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
10924 Handle<Object> delete_count_object =
10925 isolate->factory()->NewNumberFromUint(delete_count);
10926 Handle<Object> add_count_object =
10927 isolate->factory()->NewNumberFromUint(add_count);
10928
10929 Handle<Object> args[] =
10930 { object, index_object, deleted, delete_count_object, add_count_object };
10931
10932 bool threw;
10933 Execution::Call(Handle<JSFunction>(isolate->observers_enqueue_splice()),
10934 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
10935 &threw);
10936 ASSERT(!threw);
10937 }
10938
10939
10940 static void BeginPerformSplice(Handle<JSArray> object) {
10941 Isolate* isolate = object->GetIsolate();
10942 HandleScope scope(isolate);
10943 Handle<Object> args[] = { object };
10944
10945 bool threw;
10946 Execution::Call(Handle<JSFunction>(isolate->observers_begin_perform_splice()),
10947 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
10948 &threw);
10949 ASSERT(!threw);
10950 }
10951
10952
10953 static void EndPerformSplice(Handle<JSArray> object) {
10954 Isolate* isolate = object->GetIsolate();
10955 HandleScope scope(isolate);
10956 Handle<Object> args[] = { object };
10957
10958 bool threw;
10959 Execution::Call(Handle<JSFunction>(isolate->observers_end_perform_splice()),
10960 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
10961 &threw);
10962 ASSERT(!threw);
10963 }
10964
10965
10914 MaybeObject* JSArray::SetElementsLength(Object* len) { 10966 MaybeObject* JSArray::SetElementsLength(Object* len) {
10915 // We should never end in here with a pixel or external array. 10967 // We should never end in here with a pixel or external array.
10916 ASSERT(AllowsSetElementsLength()); 10968 ASSERT(AllowsSetElementsLength());
10917 if (!(FLAG_harmony_observation && map()->is_observed())) 10969 if (!(FLAG_harmony_observation && map()->is_observed()))
10918 return GetElementsAccessor()->SetLength(this, len); 10970 return GetElementsAccessor()->SetLength(this, len);
10919 10971
10920 Isolate* isolate = GetIsolate(); 10972 Isolate* isolate = GetIsolate();
10921 HandleScope scope(isolate); 10973 HandleScope scope(isolate);
10922 Handle<JSArray> self(this); 10974 Handle<JSArray> self(this);
10923 List<Handle<String> > indices; 10975 List<uint32_t> indices;
10924 List<Handle<Object> > old_values; 10976 List<Handle<Object> > old_values;
10925 Handle<Object> old_length_handle(self->length(), isolate); 10977 Handle<Object> old_length_handle(self->length(), isolate);
10926 Handle<Object> new_length_handle(len, isolate); 10978 Handle<Object> new_length_handle(len, isolate);
10927 uint32_t old_length = 0; 10979 uint32_t old_length = 0;
10928 CHECK(old_length_handle->ToArrayIndex(&old_length)); 10980 CHECK(old_length_handle->ToArrayIndex(&old_length));
10929 uint32_t new_length = 0; 10981 uint32_t new_length = 0;
10930 if (!new_length_handle->ToArrayIndex(&new_length)) 10982 if (!new_length_handle->ToArrayIndex(&new_length))
10931 return Failure::InternalError(); 10983 return Failure::InternalError();
10932 10984
10933 // Observed arrays should always be in dictionary mode; 10985 // Observed arrays should always be in dictionary mode;
(...skipping 19 matching lines...) Expand all
10953 } 11005 }
10954 } 11006 }
10955 } 11007 }
10956 11008
10957 MaybeObject* result = 11009 MaybeObject* result =
10958 self->GetElementsAccessor()->SetLength(*self, *new_length_handle); 11010 self->GetElementsAccessor()->SetLength(*self, *new_length_handle);
10959 Handle<Object> hresult; 11011 Handle<Object> hresult;
10960 if (!result->ToHandle(&hresult, isolate)) return result; 11012 if (!result->ToHandle(&hresult, isolate)) return result;
10961 11013
10962 CHECK(self->length()->ToArrayIndex(&new_length)); 11014 CHECK(self->length()->ToArrayIndex(&new_length));
10963 if (old_length != new_length) { 11015 if (old_length == new_length) return *hresult;
10964 for (int i = 0; i < indices.length(); ++i) { 11016
10965 JSObject::EnqueueChangeRecord( 11017 BeginPerformSplice(self);
10966 self, "deleted", indices[i], old_values[i]); 11018
11019 for (int i = 0; i < indices.length(); ++i) {
11020 JSObject::EnqueueChangeRecord(
11021 self, "deleted", isolate->factory()->Uint32ToString(indices[i]),
11022 old_values[i]);
11023 }
11024 JSObject::EnqueueChangeRecord(
11025 self, "updated", isolate->factory()->length_string(),
11026 old_length_handle);
11027
11028 EndPerformSplice(self);
11029
11030 uint32_t index = Min(old_length, new_length);
11031 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
rossberg 2013/05/27 14:48:41 Max(new_length - old_length, 0)
rafaelw 2013/05/28 11:38:53 new_length and old_length are both uint so, withou
rossberg 2013/06/04 10:56:58 OK, I see.
11032 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
rossberg 2013/05/27 14:48:41 Max(old_length - new_length, 0)
rafaelw 2013/05/28 11:38:53 Same here. On 2013/05/27 14:48:41, rossberg wrote
11033 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
11034 if (delete_count) {
rossberg 2013/05/27 14:48:41 Nit: delete_count > 0
rafaelw 2013/05/28 11:38:53 Done.
11035 int i = indices.length();
11036 while (i--) {
rossberg 2013/05/27 14:48:41 Can we make this a for loop?
rafaelw 2013/05/28 11:38:53 I'm curious why you prefer the for loop, but I've
rossberg 2013/06/04 10:56:58 I'm curious why you're curious. ;) It is just an i
11037 JSObject::SetElement(deleted, indices[i] - index, old_values[i], NONE,
11038 kNonStrictMode);
10967 } 11039 }
10968 JSObject::EnqueueChangeRecord(
10969 self, "updated", isolate->factory()->length_string(),
10970 old_length_handle);
10971 } 11040 }
11041
11042 EnqueueSpliceRecord(self, index, deleted, delete_count, add_count);
11043
10972 return *hresult; 11044 return *hresult;
10973 } 11045 }
10974 11046
10975 11047
10976 Map* Map::GetPrototypeTransition(Object* prototype) { 11048 Map* Map::GetPrototypeTransition(Object* prototype) {
10977 FixedArray* cache = GetPrototypeTransitions(); 11049 FixedArray* cache = GetPrototypeTransitions();
10978 int number_of_transitions = NumberOfProtoTransitions(); 11050 int number_of_transitions = NumberOfProtoTransitions();
10979 const int proto_offset = 11051 const int proto_offset =
10980 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset; 11052 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
10981 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; 11053 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
(...skipping 1004 matching lines...) Expand 10 before | Expand all | Expand 10 after
11986 index, value_raw, attributes, strict_mode, check_prototype, set_mode) 12058 index, value_raw, attributes, strict_mode, check_prototype, set_mode)
11987 : SetElementWithoutInterceptor( 12059 : SetElementWithoutInterceptor(
11988 index, value_raw, attributes, strict_mode, check_prototype, set_mode); 12060 index, value_raw, attributes, strict_mode, check_prototype, set_mode);
11989 } 12061 }
11990 12062
11991 // From here on, everything has to be handlified. 12063 // From here on, everything has to be handlified.
11992 Handle<JSObject> self(this); 12064 Handle<JSObject> self(this);
11993 Handle<Object> value(value_raw, isolate); 12065 Handle<Object> value(value_raw, isolate);
11994 PropertyAttributes old_attributes = self->GetLocalElementAttribute(index); 12066 PropertyAttributes old_attributes = self->GetLocalElementAttribute(index);
11995 Handle<Object> old_value = isolate->factory()->the_hole_value(); 12067 Handle<Object> old_value = isolate->factory()->the_hole_value();
11996 Handle<Object> old_length; 12068 Handle<Object> old_length_handle;
12069 Handle<Object> new_length_handle;
rossberg 2013/05/27 14:48:41 Move this and new_length into conditional below, t
rafaelw 2013/05/28 11:38:53 Done.
12070 uint32_t old_length = 0;
12071 uint32_t new_length = 0;
11997 12072
11998 if (old_attributes != ABSENT) { 12073 if (old_attributes != ABSENT) {
11999 if (self->GetLocalElementAccessorPair(index) == NULL) 12074 if (self->GetLocalElementAccessorPair(index) == NULL)
12000 old_value = Object::GetElement(self, index); 12075 old_value = Object::GetElement(self, index);
12001 } else if (self->IsJSArray()) { 12076 } else if (self->IsJSArray()) {
12002 // Store old array length in case adding an element grows the array. 12077 // Store old array length in case adding an element grows the array.
12003 old_length = handle(Handle<JSArray>::cast(self)->length(), isolate); 12078 old_length_handle = handle(Handle<JSArray>::cast(self)->length(), isolate);
12079 CHECK(old_length_handle->ToArrayIndex(&old_length));
12004 } 12080 }
12005 12081
12006 // Check for lookup interceptor 12082 // Check for lookup interceptor
12007 MaybeObject* result = self->HasIndexedInterceptor() 12083 MaybeObject* result = self->HasIndexedInterceptor()
12008 ? self->SetElementWithInterceptor( 12084 ? self->SetElementWithInterceptor(
12009 index, *value, attributes, strict_mode, check_prototype, set_mode) 12085 index, *value, attributes, strict_mode, check_prototype, set_mode)
12010 : self->SetElementWithoutInterceptor( 12086 : self->SetElementWithoutInterceptor(
12011 index, *value, attributes, strict_mode, check_prototype, set_mode); 12087 index, *value, attributes, strict_mode, check_prototype, set_mode);
12012 12088
12013 Handle<Object> hresult; 12089 Handle<Object> hresult;
12014 if (!result->ToHandle(&hresult, isolate)) return result; 12090 if (!result->ToHandle(&hresult, isolate)) return result;
12015 12091
12016 Handle<String> name = isolate->factory()->Uint32ToString(index); 12092 Handle<String> name = isolate->factory()->Uint32ToString(index);
12017 PropertyAttributes new_attributes = self->GetLocalElementAttribute(index); 12093 PropertyAttributes new_attributes = self->GetLocalElementAttribute(index);
12018 if (old_attributes == ABSENT) { 12094 if (old_attributes == ABSENT) {
12095 bool array_extended = false;
rossberg 2013/05/27 14:48:41 Can we initialize this properly instead of mutatin
rafaelw 2013/05/28 11:38:53 Done.
12096 if (self->IsJSArray() &&
12097 !old_length_handle->SameValue(Handle<JSArray>::cast(self)->length())) {
12098 array_extended = true;
12099 new_length_handle = handle(Handle<JSArray>::cast(self)->length(),
12100 isolate);
12101 CHECK(new_length_handle->ToArrayIndex(&new_length));
12102 BeginPerformSplice(Handle<JSArray>::cast(self));
12103 }
12104
12019 EnqueueChangeRecord(self, "new", name, old_value); 12105 EnqueueChangeRecord(self, "new", name, old_value);
12020 if (self->IsJSArray() && 12106 if (array_extended) {
12021 !old_length->SameValue(Handle<JSArray>::cast(self)->length())) { 12107 EnqueueChangeRecord(self, "updated", isolate->factory()->length_string(),
12022 EnqueueChangeRecord( 12108 old_length_handle);
12023 self, "updated", isolate->factory()->length_string(), old_length); 12109
12110 EndPerformSplice(Handle<JSArray>::cast(self));
12111 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
12112 EnqueueSpliceRecord(Handle<JSArray>::cast(self), old_length, deleted, 0,
12113 new_length - old_length);
12024 } 12114 }
12025 } else if (old_value->IsTheHole()) { 12115 } else if (old_value->IsTheHole()) {
12026 EnqueueChangeRecord(self, "reconfigured", name, old_value); 12116 EnqueueChangeRecord(self, "reconfigured", name, old_value);
12027 } else { 12117 } else {
12028 Handle<Object> new_value = Object::GetElement(self, index); 12118 Handle<Object> new_value = Object::GetElement(self, index);
12029 bool value_changed = !old_value->SameValue(*new_value); 12119 bool value_changed = !old_value->SameValue(*new_value);
12030 if (old_attributes != new_attributes) { 12120 if (old_attributes != new_attributes) {
12031 if (!value_changed) old_value = isolate->factory()->the_hole_value(); 12121 if (!value_changed) old_value = isolate->factory()->the_hole_value();
12032 EnqueueChangeRecord(self, "reconfigured", name, old_value); 12122 EnqueueChangeRecord(self, "reconfigured", name, old_value);
12033 } else if (value_changed) { 12123 } else if (value_changed) {
(...skipping 3599 matching lines...) Expand 10 before | Expand all | Expand 10 after
15633 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 15723 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
15634 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 15724 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
15635 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 15725 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
15636 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 15726 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
15637 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 15727 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
15638 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 15728 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
15639 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 15729 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
15640 } 15730 }
15641 15731
15642 } } // namespace v8::internal 15732 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/contexts.h ('k') | src/v8natives.js » ('j') | src/v8natives.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698