From 7c238db8297e0ce6b5b9c079f1703d4b1b16b7d3 Mon Sep 17 00:00:00 2001 From: "antonm@chromium.org" Date: Tue, 5 Oct 2010 13:10:43 +0000 Subject: [PATCH] Do not shortcut union of keys if lhs is empty. The problem is other array may have holes, for example when fixed array comes from JSArray (in case of named interceptor). If that would prove to be a performance problem, we could pass an additional argument into UnionOfKeys to hold actual length. Review URL: http://codereview.chromium.org/3595013 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5591 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/handles.cc | 15 +++++++++++++++ src/objects.cc | 20 ++++++++++++++++---- test/cctest/test-api.cc | 28 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/handles.cc b/src/handles.cc index 759d7ce..8fe29bb 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -635,8 +635,19 @@ v8::Handle GetKeysForIndexedInterceptor(Handle receiver, } +static bool ContainsOnlyValidKeys(Handle array) { + int len = array->length(); + for (int i = 0; i < len; i++) { + Object* e = array->get(i); + if (!(e->IsString() || e->IsNumber())) return false; + } + return true; +} + + Handle GetKeysInFixedArrayFor(Handle object, KeyCollectionType type) { + USE(ContainsOnlyValidKeys); Handle content = Factory::empty_fixed_array(); Handle arguments_boilerplate = Handle( @@ -664,6 +675,7 @@ Handle GetKeysInFixedArrayFor(Handle object, Factory::NewFixedArray(current->NumberOfEnumElements()); current->GetEnumElementKeys(*element_keys); content = UnionOfKeys(content, element_keys); + ASSERT(ContainsOnlyValidKeys(content)); // Add the element keys from the interceptor. if (current->HasIndexedInterceptor()) { @@ -671,6 +683,7 @@ Handle GetKeysInFixedArrayFor(Handle object, GetKeysForIndexedInterceptor(object, current); if (!result.IsEmpty()) content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); + ASSERT(ContainsOnlyValidKeys(content)); } // We can cache the computed property keys if access checks are @@ -692,6 +705,7 @@ Handle GetKeysInFixedArrayFor(Handle object, // Compute the property keys and cache them if possible. content = UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); + ASSERT(ContainsOnlyValidKeys(content)); // Add the property keys from the interceptor. if (current->HasNamedInterceptor()) { @@ -699,6 +713,7 @@ Handle GetKeysInFixedArrayFor(Handle object, GetKeysForNamedInterceptor(object, current); if (!result.IsEmpty()) content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); + ASSERT(ContainsOnlyValidKeys(content)); } // If we only want local properties we bail out after the first diff --git a/src/objects.cc b/src/objects.cc index 1a3dc4e..883d789 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -3601,9 +3601,17 @@ Object* FixedArray::AddKeysFromJSArray(JSArray* array) { Object* FixedArray::UnionOfKeys(FixedArray* other) { int len0 = length(); +#ifdef DEBUG + if (FLAG_enable_slow_asserts) { + for (int i = 0; i < len0; i++) { + ASSERT(get(i)->IsString() || get(i)->IsNumber()); + } + } +#endif int len1 = other->length(); - // Optimize if either is empty. - if (len0 == 0) return other; + // Optimize if 'other' is empty. + // We cannot optimize if 'this' is empty, as other may have holes + // or non keys. if (len1 == 0) return this; // Compute how many elements are not in this. @@ -3623,14 +3631,18 @@ Object* FixedArray::UnionOfKeys(FixedArray* other) { FixedArray* result = FixedArray::cast(obj); WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); for (int i = 0; i < len0; i++) { - result->set(i, get(i), mode); + Object* e = get(i); + ASSERT(e->IsString() || e->IsNumber()); + result->set(i, e, mode); } // Fill in the extra keys. int index = 0; for (int y = 0; y < len1; y++) { Object* value = other->get(y); if (!value->IsTheHole() && !HasKey(this, value)) { - result->set(len0 + index, other->get(y), mode); + Object* e = other->get(y); + ASSERT(e->IsString() || e->IsNumber()); + result->set(len0 + index, e, mode); index++; } } diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 12eabbd..af50d3d 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -11727,3 +11727,31 @@ TEST(RegExp) { context->Global()->Set(v8_str("ex"), try_catch.Exception()); ExpectTrue("ex instanceof SyntaxError"); } + + +static v8::Handle Getter(v8::Local property, + const v8::AccessorInfo& info ) { + return v8_str("42!"); +} + + +static v8::Handle Enumerator(const v8::AccessorInfo& info) { + v8::Handle result = v8::Array::New(); + result->Set(0, v8_str("universalAnswer")); + return result; +} + + +TEST(NamedEnumeratorAndForIn) { + v8::HandleScope handle_scope; + LocalContext context; + v8::Context::Scope context_scope(context.local()); + + v8::Handle tmpl = v8::ObjectTemplate::New(); + tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator); + context->Global()->Set(v8_str("o"), tmpl->NewInstance()); + v8::Handle result = v8::Handle::Cast(CompileRun( + "var result = []; for (var k in o) result.push(k); result")); + CHECK_EQ(1, result->Length()); + CHECK_EQ(v8_str("universalAnswer"), result->Get(0)); +} -- 2.7.4