Reland [ic] Remove the check for fast prototypes in LoadIC_Uninitialized

This is a reland of d14ed12e56
with fix for test failures in lite mode.

When handling load named properties (without feedback vectors) we used
to miss to runtimes if the prototypes aren't set. This was because we
wanted to give the prototype a chance to become fast, since most prototypes
start in slow mode but move to fast after the initial setup. Though this
check is not really useful when we don't have feedback vectors, and once
feedback vectors are allocated we will turn the prototypes fast anyway.

Bug: v8:8394, v8:8860
Change-Id: I5c7b5061e1d9068c72d6f0eea47517880940a054
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1591772
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Mythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61267}
This commit is contained in:
Mythri A 2019-05-01 14:05:49 +01:00 committed by Commit Bot
parent c0bc087b26
commit 9fe37d238e
6 changed files with 54 additions and 72 deletions

View File

@ -2604,46 +2604,15 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
}
}
// TODO(8860): This check is only required so we can make prototypes fast on
// the first load. This is not really useful when there is no feedback vector
// and may not be important when lazily allocating feedback vectors. Once lazy
// allocation of feedback vectors has landed try to eliminate this check.
void AccessorAssembler::BranchIfPrototypeShouldbeFast(Node* receiver_map,
Label* prototype_not_fast,
Label* prototype_fast) {
VARIABLE(var_map, MachineRepresentation::kTagged);
var_map.Bind(receiver_map);
Label loop_body(this, &var_map);
Goto(&loop_body);
BIND(&loop_body);
{
Node* map = var_map.value();
Node* prototype = LoadMapPrototype(map);
GotoIf(IsNull(prototype), prototype_fast);
TNode<PrototypeInfo> proto_info =
LoadMapPrototypeInfo(receiver_map, prototype_not_fast);
GotoIf(IsNull(prototype), prototype_not_fast);
TNode<Uint32T> flags =
LoadObjectField<Uint32T>(proto_info, PrototypeInfo::kBitFieldOffset);
GotoIf(Word32Equal(flags, Uint32Constant(0)), prototype_not_fast);
Node* prototype_map = LoadMap(prototype);
var_map.Bind(prototype_map);
Goto(&loop_body);
}
}
void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
Label miss(this, Label::kDeferred),
check_if_fast_prototype(this, Label::kDeferred),
check_function_prototype(this);
Node* receiver = p->receiver;
GotoIf(TaggedIsSmi(receiver), &miss);
Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map);
GotoIf(IsUndefined(p->vector), &check_if_fast_prototype);
GotoIf(IsUndefined(p->vector), &check_function_prototype);
// Optimistically write the state transition to the vector.
StoreFeedbackVectorSlot(p->vector, p->slot,
LoadRoot(RootIndex::kpremonomorphic_symbol),
@ -2652,12 +2621,6 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
kTaggedSize, SMI_PARAMETERS);
Goto(&check_function_prototype);
BIND(&check_if_fast_prototype);
{
BranchIfPrototypeShouldbeFast(receiver_map, &miss,
&check_function_prototype);
}
BIND(&check_function_prototype);
{
// Special case for Function.prototype load, because it's very common

View File

@ -296,10 +296,6 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
Representation representation, Node* value,
Label* bailout);
void BranchIfPrototypeShouldbeFast(Node* receiver_map,
Label* prototype_not_fast,
Label* prototype_fast);
// Extends properties backing store by JSObject::kFieldsAdded elements,
// returns updated properties backing store.
Node* ExtendPropertiesBackingStore(Node* object, Node* index);

View File

@ -47,6 +47,7 @@ function TestAddingPropertyToDictionaryPrototype() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingPropertyToDictionaryPrototype);
TestAddingPropertyToDictionaryPrototype();
// Same as TestAddingPropertyToDictionaryPrototype, but using o["foo"] access
@ -82,6 +83,7 @@ function TestAddingPropertyToDictionaryPrototype2() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingPropertyToDictionaryPrototype2);
TestAddingPropertyToDictionaryPrototype2();
function TestAddingPropertyToDictionaryPrototype_DefineProperty() {
@ -113,6 +115,7 @@ function TestAddingPropertyToDictionaryPrototype_DefineProperty() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingPropertyToDictionaryPrototype_DefineProperty);
TestAddingPropertyToDictionaryPrototype_DefineProperty();
function TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath() {
@ -146,6 +149,7 @@ function TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath);
TestAddingPropertyToDictionaryPrototype_DictionaryAddSlowPath();
function TestAddingAccessorPropertyToDictionaryPrototype() {
@ -177,6 +181,7 @@ function TestAddingAccessorPropertyToDictionaryPrototype() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingAccessorPropertyToDictionaryPrototype);
TestAddingAccessorPropertyToDictionaryPrototype();
function TestRemovingPropertyFromDictionaryPrototype() {
@ -208,6 +213,7 @@ function TestRemovingPropertyFromDictionaryPrototype() {
assertEquals(10, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestRemovingPropertyFromDictionaryPrototype);
TestRemovingPropertyFromDictionaryPrototype();
// Same as TestRemovingPropertyFromDictionaryPrototype, but using o["foo"] access
@ -242,6 +248,7 @@ function TestRemovingPropertyFromDictionaryPrototype2() {
assertEquals(10, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestRemovingPropertyFromDictionaryPrototype2);
TestRemovingPropertyFromDictionaryPrototype2();
function TestAddingPropertyToDictionaryPrototype_Monomorphic() {
@ -286,6 +293,7 @@ function TestAddingPropertyToDictionaryPrototype_Monomorphic() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingPropertyToDictionaryPrototype_Monomorphic);
TestAddingPropertyToDictionaryPrototype_Monomorphic();
function TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic() {
@ -331,6 +339,7 @@ function TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic);
TestAddingKeyedPropertyToDictionaryPrototype_Monomorphic();
// Like TestAddingPropertyToDictionaryPrototype, except that the prototype isn't
@ -369,6 +378,7 @@ function TestAddingPropertyToAlmostDictionaryPrototype() {
assertEquals(1, bar_func_called);
}
%EnsureFeedbackVectorForFunction(TestAddingPropertyToAlmostDictionaryPrototype);
TestAddingPropertyToAlmostDictionaryPrototype();
function TestReconfiguringDataToAccessor() {
@ -406,4 +416,5 @@ function TestReconfiguringDataToAccessor() {
assertEquals(1, setter_called);
}
%EnsureFeedbackVectorForFunction(TestReconfiguringDataToAccessor);
TestReconfiguringDataToAccessor();

View File

@ -43,6 +43,7 @@ function AddProps(obj) {
obj["x" + i] = 0;
}
}
%EnsureFeedbackVectorForFunction(AddProps);
function DoProtoMagic(proto, set__proto__) {
@ -58,9 +59,11 @@ function DoProtoMagic(proto, set__proto__) {
}
// Prototypes are made fast when ICs encounter them.
function ic() { return typeof receiver.foo; }
%EnsureFeedbackVectorForFunction(ic);
ic();
ic();
}
%EnsureFeedbackVectorForFunction(DoProtoMagic);
function test(use_new, add_first, set__proto__) {
@ -86,36 +89,41 @@ function test(use_new, add_first, set__proto__) {
}
return proto;
}
%EnsureFeedbackVectorForFunction(test);
// TODO(mstarzinger): This test fails easily if gc happens at the wrong time.
gc();
for (var i = 0; i < 4; i++) {
var set__proto__ = ((i & 1) != 0);
var use_new = ((i & 2) != 0);
function test_fast_prototype() {
for (var i = 0; i < 4; i++) {
var set__proto__ = ((i & 1) != 0);
var use_new = ((i & 2) != 0);
test(use_new, true, set__proto__);
test(use_new, false, set__proto__);
}
test(use_new, true, set__proto__);
test(use_new, false, set__proto__);
}
var x = {a: 1, b: 2, c: 3};
var o = { __proto__: x };
assertFalse(%HasFastProperties(x));
for (key in x) {
assertTrue(key == 'a');
break;
}
assertTrue(%HasFastProperties(x));
delete x.b;
for (key in x) {
assertTrue(key == 'a');
break;
}
assertTrue(%HasFastProperties(x));
x.d = 4;
assertTrue(%HasFastProperties(x));
for (key in x) {
assertTrue(key == 'a');
break;
var x = {a: 1, b: 2, c: 3};
var o = { __proto__: x };
assertFalse(%HasFastProperties(x));
for (key in x) {
assertTrue(key == 'a');
break;
}
assertTrue(%HasFastProperties(x));
delete x.b;
for (key in x) {
assertTrue(key == 'a');
break;
}
assertTrue(%HasFastProperties(x));
x.d = 4;
assertTrue(%HasFastProperties(x));
for (key in x) {
assertTrue(key == 'a');
break;
}
}
%EnsureFeedbackVectorForFunction(test_fast_prototype);
test_fast_prototype();

View File

@ -21,6 +21,7 @@ A.prototype = proto;
function foo(o) {
return o.a0;
}
%EnsureFeedbackVectorForFunction(foo);
// Ensure |proto| is in old space.
gc();

View File

@ -6,13 +6,16 @@
(function Test() {
var f = () => 42;
delete f.length;
delete f.name;
function modify_f() {
delete f.length;
delete f.name;
var g = Object.create(f);
for (var i = 0; i < 5; i++) {
g.dummy;
var g = Object.create(f);
for (var i = 0; i < 5; i++) {
g.dummy;
}
}
%EnsureFeedbackVectorForFunction(f);
assertTrue(%HasFastProperties(f));
var h = f.bind(this);