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
}
+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>(
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()) {
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
// 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()) {
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
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.
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++;
}
}
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));
+}