Commit 300573ac authored by Frank Emrich's avatar Frank Emrich Committed by Commit Bot

[classes] Fix enumeration order bugs when accessors shadow dynamic prop.

AddToDictionaryTemplate in literal-objects.cc was missing several
cases when handling the overwriting between properties with statically
known and dynamically computed names. This led to wrong enumeration
orders in class prototypes created from class templates.

Bug: v8:11158
Change-Id: I7381b4680ec533bd307a6c32d75c8a66394869df
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2536464
Commit-Queue: Frank Emrich <emrich@google.com>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71266}
parent 4bf24d11
This diff is collapsed.
......@@ -509,3 +509,229 @@ function assertIteratorResult(value, done, result) {
}
}, ReferenceError);
})();
// The following tests deal with computed and statically known properties
// of the same name overwriting each other.
//
// More concretely, we consider the cases where:
// The computed property appears ...
// - before an existing data property (case 1)
// - after an existing data property (case 2)
// - before an existing getter and setter pair (case 3)
// - before an existing getter xor setter (case 4)
// - after an existing getter and setter pair (case 5)
// - after an existing getter xor setter (case 6)
// - in between two existing accessors (case 7)
//
// For each of the 7 cases above, there exists A and B variants, indicating
// whether the computed property refers to an accessor (variant A) or a
// plain property (variant B).
// |expect_getter| and |expect_setter| must be undefined if and only if we are
// expecting |b| to be a data property.
function TestOverwritingHelper(clazz, expect_getter, expect_setter) {
var proto = clazz.prototype;
var desc = Object.getOwnPropertyDescriptor(proto, 'b');
if (desc.hasOwnProperty('value')) {
assertEquals(undefined, expect_getter);
assertEquals(undefined, expect_setter);
assertEquals('B', proto.b());
} else {
assertEquals("boolean", typeof expect_getter);
assertEquals("boolean", typeof expect_setter);
if (expect_getter) {
assertEquals('B', proto.b);
} else {
assertEquals(undefined, desc.getter);
}
assertEquals(expect_setter, desc.set !== undefined);
}
assertEquals('A', proto.a());
assertEquals('C', proto.c());
assertEquals('D', proto.d());
assertArrayEquals([], Object.keys(proto));
assertArrayEquals(['constructor', 'a', 'b', 'c', 'd'],
Object.getOwnPropertyNames(proto));
}
(function TestOverwriting1A() {
class C {
a() { return 'A'}
get [ID('b')]() { return 'Bx'; }
c() { return 'C'; }
b() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C);
})();
(function TestOverwriting1B() {
class C {
a() { return 'A'}
[ID('b')]() { return 'Bx'; }
c() { return 'C'; }
b() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C);
})();
(function TestOverwriting2A() {
class C {
a() { return 'A'}
b() { return 'Bx'; }
c() { return 'C'; }
get [ID('b')]() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C, true, false);
})();
(function TestOverwriting2B() {
class C {
a() { return 'A'}
b() { return 'Bx'; }
c() { return 'C'; }
[ID('b')]() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C);
})();
(function TestOverwriting3A() {
class C {
a() { return 'A'}
get [ID('b')]() { return 'Bx'; }
c() { return 'C'; }
get b() { return 'B'; }
set b(foo) { this.x = foo; }
d() { return 'D'; }
}
TestOverwritingHelper(C, true, true);
})();
(function TestOverwriting3B() {
class C {
a() { return 'A'}
[ID('b')]() { return 'Bx'; }
c() { return 'C'; }
get b() { return 'B'; }
set b(foo) { this.x = foo; }
d() { return 'D'; }
}
TestOverwritingHelper(C, true, true);
})();
(function TestOverwriting4A() {
class C {
a() { return 'A'}
get [ID('b')]() { return 'Bx'; }
c() { return 'C'; }
get b() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C, true, false);
})();
(function TestOverwriting4B() {
class C {
a() { return 'A'}
[ID('b')]() { return 'Bx'; }
c() { return 'C'; }
get b() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C, true, false);
})();
(function TestOverwriting5A() {
class C {
a() { return 'A'}
get b() { return 'Bx'; }
set b(foo) { this.x = foo; }
c() { return 'C'; }
get [ID('b')]() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C, true, true);
})();
(function TestOverwriting5B() {
class C {
a() { return 'A'}
get b() { return 'Bx'; }
set b(foo) { this.x = foo; }
c() { return 'C'; }
[ID('b')]() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C);
})();
(function TestOverwriting6A() {
class C {
a() { return 'A'}
set b(foo) { this.x = foo; }
c() { return 'C'; }
get [ID('b')]() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C, true, true);
})();
(function TestOverwriting6B() {
class C {
a() { return 'A'}
set b(foo) { this.x = foo; }
c() { return 'C'; }
[ID('b')]() { return 'B'; }
d() { return 'D'; }
}
TestOverwritingHelper(C);
})();
(function TestOverwriting7A() {
class C {
a() { return 'A'}
get b() { return 'Bx'; }
c() { return 'C'; }
get [ID('b')]() { return 'B'; }
d() { return 'D'; }
set b(foo) { this.x = foo; }
}
TestOverwritingHelper(C, true, true);
})();
(function TestOverwriting7B() {
class C {
a() { return 'A'}
set b(foo) { this.x = foo; }
c() { return 'C'; }
[ID('b')]() { return 'Bx'; }
d() { return 'D'; }
get b() { return 'B'; }
}
TestOverwritingHelper(C, true, false);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment