diff --git a/src/handles.cc b/src/handles.cc index 759d7ced1b..8fe29bb7a0 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 1a3dc4e73a..883d7896c5 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 12eabbd7b4..af50d3d0ee 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)); +}