Reviewers: rafaelw, rossberg,
Message:
Just sending out so folks can take a look, this will likely be rolled up in
Rafael's patch as he writes tests for arrays.
Description:
Handle Object.observe notifications for setting Array.length
Also handles notification of deleted properties when an array
is truncated by setting length.
Still needs tests.
Please review this at https://codereview.chromium.org/11338048/
SVN Base: [email protected]:rafaelw/v8@master
Affected files:
M src/accessors.cc
M src/heap.h
M src/object-observe.cc
Index: src/accessors.cc
diff --git a/src/accessors.cc b/src/accessors.cc
index
1bc9221a20c5c973c020bfea7f90cd0a46ce4316..5e39dea8c21fe1c59c57d5546826fd0e13b23e2c
100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -35,6 +35,7 @@
#include "frames-inl.h"
#include "isolate.h"
#include "list-inl.h"
+#include "object-observe.h"
#include "property-details.h"
namespace v8 {
@@ -95,6 +96,67 @@ Object* Accessors::FlattenNumber(Object* value) {
}
+static MaybeObject* ArraySetLengthObserved(Isolate* isolate,
+ Handle<JSArray> array,
+ Handle<Object>
new_length_handle) {
+ List<Handle<Object> > indices;
+ List<Handle<Object> > old_values;
+ Handle<Object> old_length_handle(array->length(), isolate);
+ uint32_t old_length;
+ CHECK(old_length_handle->ToArrayIndex(&old_length));
+ uint32_t new_length;
+ CHECK(new_length_handle->ToArrayIndex(&new_length));
+ uint32_t end_index = old_length;
+ while (end_index && end_index-- > new_length) {
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ if (!accessor->HasElement(*array, *array, end_index))
+ continue;
+ indices.Add(isolate->factory()->NewNumberFromUint(end_index));
+ if (array->HasDictionaryElements()) {
+ // Slow case: need to make sure the element isn't a callback.
+ SeededNumberDictionary* dictionary = array->element_dictionary();
+ int entry = dictionary->FindEntry(end_index);
+ if (entry == SeededNumberDictionary::kNotFound)
+ continue;
+ // TODO: Since we have the details available here, we could
short-circuit
+ // the whole operation if we notice the element is non-configurable.
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ if (details.type() == CALLBACKS) {
+ old_values.Add(isolate->factory()->the_hole_value());
+ continue;
+ }
+ }
+ Object* element;
+ // TODO: Can this actually fail?
+ { MaybeObject* maybe_object = accessor->Get(*array, *array, end_index);
+ if (!maybe_object->ToObject(&element)) return maybe_object;
+ }
+ old_values.Add(Handle<Object>(element, isolate));
+ }
+
+ MaybeObject* result = array->SetElementsLength(*new_length_handle);
+ if (result->IsFailure()) return result;
+
+ Handle<Object> result_handle(result->ToObjectUnchecked(), isolate);
+ CHECK(array->length()->ToArrayIndex(&new_length));
+ if (old_length != new_length) {
+ if (old_length > new_length) {
+ ASSERT(old_length - new_length
+ <= static_cast<uint32_t>(indices.length()));
+ for (uint32_t i = 0; i < (old_length - new_length); ++i) {
+ ObjectObservation::EnqueueChangeRecord(
+ isolate, array, isolate->factory()->deleted_symbol(),
+ indices[i], old_values[i]);
+ }
+ }
+ ObjectObservation::EnqueueChangeRecord(
+ isolate, array, isolate->factory()->updated_symbol(),
+ isolate->factory()->length_symbol(), old_length_handle);
+ }
+ return *result_handle;
+}
+
+
MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value,
void*) {
Isolate* isolate = object->GetIsolate();
@@ -112,7 +174,7 @@ MaybeObject* Accessors::ArraySetLength(JSObject*
object, Object* value, void*) {
HandleScope scope(isolate);
// Protect raw pointers.
- Handle<JSObject> object_handle(object, isolate);
+ Handle<JSArray> array_handle(JSArray::cast(object), isolate);
Handle<Object> value_handle(value, isolate);
bool has_exception;
@@ -122,7 +184,9 @@ MaybeObject* Accessors::ArraySetLength(JSObject*
object, Object* value, void*) {
if (has_exception) return Failure::Exception();
if (uint32_v->Number() == number_v->Number()) {
- return
Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
+ return FLAG_harmony_object_observe
+ ? ArraySetLengthObserved(isolate, array_handle, uint32_v)
+ : array_handle->SetElementsLength(*uint32_v);
}
return isolate->Throw(
*isolate->factory()->NewRangeError("invalid_array_length",
Index: src/heap.h
diff --git a/src/heap.h b/src/heap.h
index
179cff8b10f9f54b7a5efbcfbf603f2a5d32eec3..f6e5b04e05c3d1d0f6c6242f6fe3955639dcc390
100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -251,7 +251,9 @@ namespace internal {
V(infinity_symbol, "Infinity") \
V(minus_infinity_symbol, "-Infinity") \
V(hidden_stack_trace_symbol, "v8::hidden_stack_trace") \
- V(query_colon_symbol, "(?:)")
+ V(query_colon_symbol, "(?:)") \
+ V(updated_symbol, "updated") \
+ V(deleted_symbol, "deleted")
// Forward declarations.
class GCTracer;
Index: src/object-observe.cc
diff --git a/src/object-observe.cc b/src/object-observe.cc
index
83c1f92bb76716398151608cb34525284046de4e..49e27a85c8d80b3eba231d439dfa8ece8219f215
100644
--- a/src/object-observe.cc
+++ b/src/object-observe.cc
@@ -53,6 +53,11 @@ void ObjectObservation::EnqueueChangeRecord(Isolate*
isolate,
Handle<Object> oldValue) {
bool threw = false;
+ // TODO: Actually pass something to JS to indicate that there
+ // is no old value
+ if (oldValue->IsTheHole())
+ oldValue = isolate->factory()->undefined_value();
+
Handle<Object> args[] = {
object, type, name, oldValue
};
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev