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
This commit is contained in:
parent
6e1d8065a4
commit
7c238db829
@ -635,8 +635,19 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
|
||||
}
|
||||
|
||||
|
||||
static bool ContainsOnlyValidKeys(Handle<FixedArray> 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<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
|
||||
KeyCollectionType type) {
|
||||
USE(ContainsOnlyValidKeys);
|
||||
Handle<FixedArray> content = Factory::empty_fixed_array();
|
||||
Handle<JSObject> arguments_boilerplate =
|
||||
Handle<JSObject>(
|
||||
@ -664,6 +675,7 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> 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<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> 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<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> 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<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> 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
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
@ -11727,3 +11727,31 @@ TEST(RegExp) {
|
||||
context->Global()->Set(v8_str("ex"), try_catch.Exception());
|
||||
ExpectTrue("ex instanceof SyntaxError");
|
||||
}
|
||||
|
||||
|
||||
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
|
||||
const v8::AccessorInfo& info ) {
|
||||
return v8_str("42!");
|
||||
}
|
||||
|
||||
|
||||
static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
|
||||
v8::Handle<v8::Array> 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<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
|
||||
tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
|
||||
context->Global()->Set(v8_str("o"), tmpl->NewInstance());
|
||||
v8::Handle<v8::Array> result = v8::Handle<v8::Array>::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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user