[test] Run late field tests in optimised mode

Fix the tests by disabling the optimisation that turns getter calls into
raw gets if the field is late, and by calling recording the null init
store in bytecode mode.

Change-Id: I8f12e3237cd32c890b5cef8d00c32940e937330d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134180
Commit-Queue: Liam Appelbe <liama@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Liam Appelbe 2020-02-04 16:51:38 +00:00 committed by commit-bot@chromium.org
parent 30e80f0a64
commit a793c36c77
8 changed files with 189 additions and 159 deletions

View file

@ -738,6 +738,10 @@ bool CallSpecializer::TryInlineImplicitInstanceGetter(InstanceCallInstr* call) {
if (field.needs_load_guard()) {
return false;
}
if (field.is_late()) {
// TODO(http://dartbug.com/40447): Inline implicit getters for late fields.
return false;
}
if (should_clone_fields_) {
field = field.CloneFromOriginal();
}

View file

@ -2017,7 +2017,14 @@ void BytecodeReaderHelper::ReadFieldDeclarations(const Class& cls,
field.set_is_extension_member(is_extension_member);
field.set_has_initializer(has_initializer);
if (!has_nontrivial_initializer) {
if (has_nontrivial_initializer) {
if (field.is_late()) {
// Late fields are initialized to Object::sentinel, which is a flavor of
// null. So we need to record that store so that the field guard doesn't
// prematurely optimise out the late field's sentinel checking logic.
field.RecordStore(Object::null_object());
}
} else {
value ^= ReadObject();
if (is_static) {
if (field.is_late() && !has_initializer) {

View file

@ -200,10 +200,6 @@ Fragment StreamingFlowGraphBuilder::BuildLateFieldInitializer(
}
return Fragment();
}
// Late fields are initialized to Object::sentinel, which is a flavor of null.
// So we need to record that store so that the field guard doesn't prematurely
// optimise out the late field's sentinel checking logic.
field.RecordStore(Object::null_object());
Fragment instructions;
instructions += LoadLocal(parsed_function()->receiver_var());

View file

@ -2121,6 +2121,13 @@ void KernelLoader::GenerateFieldAccessors(const Class& klass,
}
ASSERT(field.NeedsGetter());
if (field.is_late() && field.has_nontrivial_initializer()) {
// Late fields are initialized to Object::sentinel, which is a flavor of
// null. So we need to record that store so that the field guard doesn't
// prematurely optimise out the late field's sentinel checking logic.
field.RecordStore(Object::null_object());
}
const String& getter_name = H.DartGetterName(field_helper->canonical_name_);
const Object& script_class =
ClassForScriptAt(klass, field_helper->source_uri_index_);

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// SharedOptions=--enable-experiment=non-nullable
// VMOptions=--optimization_counter_threshold=10
import 'package:expect/expect.dart';
int initCalls = 0;
@ -25,45 +26,48 @@ class B {
}
main() {
Base a = A();
Expect.equals(0, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
// Setting Base.fieldWithInit once is ok but causes no calls to init().
a.fieldWithInit = 456;
Expect.equals(456, (a as A).superFieldWithInit);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
// Setting Base.fieldWithInit twice throws an error.
Expect.throws(() => {a.fieldWithInit = 789},
(error) => error is LateInitializationError);
Expect.equals(1, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
initCalls = 0;
for (int i = 0; i < 20; ++i) {
Base a = A();
Expect.equals(0, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
// Setting Base.fieldWithInit once is ok but causes no calls to init().
a.fieldWithInit = 456;
Expect.equals(456, (a as A).superFieldWithInit);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
// Setting Base.fieldWithInit twice throws an error.
Expect.throws(() => {a.fieldWithInit = 789},
(error) => error is LateInitializationError);
Expect.equals(1, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(1, initCalls);
initCalls = 0;
Base a2 = A();
Expect.equals(0, initCalls);
// Setting Base.fieldWithInit once is ok but causes no calls to init().
a2.fieldWithInit = 456;
Expect.equals(456, (a as A).superFieldWithInit);
Expect.equals(0, initCalls);
// Setting Base.fieldWithInit twice throws an error.
Expect.throws(() => {a2.fieldWithInit = 789},
(error) => error is LateInitializationError);
Expect.equals(0, initCalls);
Expect.equals(123, a2.fieldWithInit);
Expect.equals(456, (a as A).superFieldWithInit);
Expect.equals(1, initCalls);
Base a2 = A();
Expect.equals(0, initCalls);
// Setting Base.fieldWithInit once is ok but causes no calls to init().
a2.fieldWithInit = 456;
Expect.equals(456, (a as A).superFieldWithInit);
Expect.equals(0, initCalls);
// Setting Base.fieldWithInit twice throws an error.
Expect.throws(() => {a2.fieldWithInit = 789},
(error) => error is LateInitializationError);
Expect.equals(0, initCalls);
Expect.equals(123, a2.fieldWithInit);
Expect.equals(456, (a as A).superFieldWithInit);
Expect.equals(1, initCalls);
B b = B();
Expect.throws(
() => b.fieldWithNoInit, (error) => error is LateInitializationError);
b.fieldWithNoInit = 123;
Expect.equals(123, b.fieldWithNoInit);
Expect.throws(() => {b.fieldWithNoInit = 456},
(error) => error is LateInitializationError);
Expect.equals(123, b.fieldWithNoInit);
B b = B();
Expect.throws(
() => b.fieldWithNoInit, (error) => error is LateInitializationError);
b.fieldWithNoInit = 123;
Expect.equals(123, b.fieldWithNoInit);
Expect.throws(() => {b.fieldWithNoInit = 456},
(error) => error is LateInitializationError);
Expect.equals(123, b.fieldWithNoInit);
initCalls = 0;
}
}

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// SharedOptions=--enable-experiment=non-nullable
// VMOptions=--optimization_counter_threshold=10
import 'package:expect/expect.dart';
int initCalls = 0;
@ -12,28 +13,31 @@ int init() {
}
main() {
late final int fieldWithInit = init();
Expect.equals(0, initCalls);
Expect.equals(123, fieldWithInit);
Expect.equals(1, initCalls);
Expect.equals(123, fieldWithInit);
Expect.equals(1, initCalls);
for (int i = 0; i < 20; ++i) {
late final int fieldWithInit = init();
Expect.equals(0, initCalls);
Expect.equals(123, fieldWithInit);
Expect.equals(1, initCalls);
Expect.equals(123, fieldWithInit);
Expect.equals(1, initCalls);
late final int fieldWithNoInit;
Expect.throws(
() => fieldWithNoInit,
(error) => error is LateInitializationError,
);
// Confuse the definite assignment analysis.
if (1 > 0) {
fieldWithNoInit = 123;
late final int fieldWithNoInit;
Expect.throws(
() => fieldWithNoInit,
(error) => error is LateInitializationError,
);
// Confuse the definite assignment analysis.
if (1 > 0) {
fieldWithNoInit = 123;
}
Expect.equals(123, fieldWithNoInit);
Expect.throws(
() {
fieldWithNoInit = 456;
},
(error) => error is LateInitializationError,
);
Expect.equals(123, fieldWithNoInit);
initCalls = 0;
}
Expect.equals(123, fieldWithNoInit);
Expect.throws(
() {
fieldWithNoInit = 456;
},
(error) => error is LateInitializationError,
);
Expect.equals(123, fieldWithNoInit);
}

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// SharedOptions=--enable-experiment=non-nullable
// VMOptions=--optimization_counter_threshold=10
import 'package:expect/expect.dart';
int initCalls = 0;
@ -12,59 +13,62 @@ int init() {
}
main() {
late int varWithInit = init();
late int varWithTrivialInit = 123;
late int? varWithNullInit = null;
late int varWithNoInit;
Expect.equals(0, initCalls);
Expect.equals(123, varWithInit);
Expect.equals(123, varWithTrivialInit);
Expect.equals(null, varWithNullInit);
Expect.throws(
() => varWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
Expect.equals(123, varWithInit);
Expect.equals(123, varWithTrivialInit);
Expect.equals(null, varWithNullInit);
Expect.throws(
() => varWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
varWithInit = 456;
varWithTrivialInit = 456;
varWithNullInit = 456;
varWithNoInit = 456;
Expect.equals(1, initCalls);
Expect.equals(456, varWithInit);
Expect.equals(456, varWithTrivialInit);
Expect.equals(456, varWithNullInit);
Expect.equals(456, varWithNoInit);
Expect.equals(1, initCalls);
initCalls = 0;
late int varWithInit2 = init();
Expect.equals(0, initCalls);
varWithInit2 = 456;
Expect.equals(0, initCalls);
Expect.equals(456, varWithInit2);
Expect.equals(0, initCalls);
late int? varWithInit3 = init();
Expect.equals(0, initCalls);
varWithInit3 = null;
Expect.equals(0, initCalls);
Expect.equals(null, varWithInit3);
Expect.equals(0, initCalls);
late int varWithCondInit = null ?? init();
var lambda = () {
Expect.equals(123, varWithCondInit);
for (int i = 0; i < 20; ++i) {
late int varWithInit = init();
late int varWithTrivialInit = 123;
late int? varWithNullInit = null;
late int varWithNoInit;
Expect.equals(0, initCalls);
Expect.equals(123, varWithInit);
Expect.equals(123, varWithTrivialInit);
Expect.equals(null, varWithNullInit);
Expect.throws(
() => varWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
};
lambda();
lambda();
lambda();
initCalls = 0;
Expect.equals(123, varWithInit);
Expect.equals(123, varWithTrivialInit);
Expect.equals(null, varWithNullInit);
Expect.throws(
() => varWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
varWithInit = 456;
varWithTrivialInit = 456;
varWithNullInit = 456;
varWithNoInit = 456;
Expect.equals(1, initCalls);
Expect.equals(456, varWithInit);
Expect.equals(456, varWithTrivialInit);
Expect.equals(456, varWithNullInit);
Expect.equals(456, varWithNoInit);
Expect.equals(1, initCalls);
initCalls = 0;
if (true) late int varNotInBlock = init();
Expect.equals(0, initCalls);
late int varWithInit2 = init();
Expect.equals(0, initCalls);
varWithInit2 = 456;
Expect.equals(0, initCalls);
Expect.equals(456, varWithInit2);
Expect.equals(0, initCalls);
late int? varWithInit3 = init();
Expect.equals(0, initCalls);
varWithInit3 = null;
Expect.equals(0, initCalls);
Expect.equals(null, varWithInit3);
Expect.equals(0, initCalls);
late int varWithCondInit = null ?? init();
var lambda = () {
Expect.equals(123, varWithCondInit);
Expect.equals(1, initCalls);
};
lambda();
lambda();
lambda();
initCalls = 0;
if (true) late int varNotInBlock = init();
Expect.equals(0, initCalls);
initCalls = 0;
}
}

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// SharedOptions=--enable-experiment=non-nullable
// VMOptions=--optimization_counter_threshold=10
import 'package:expect/expect.dart';
int initCalls = 0;
@ -19,46 +20,49 @@ class A {
}
main() {
// Late, non-final, with init.
var a = A();
Expect.equals(0, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(123, a.fieldWithTrivialInit);
Expect.equals(null, a.fieldWithNullInit);
Expect.throws(
() => a.fieldWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(123, a.fieldWithTrivialInit);
Expect.equals(null, a.fieldWithNullInit);
Expect.throws(
() => a.fieldWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
a.fieldWithInit = 456;
a.fieldWithTrivialInit = 456;
a.fieldWithNullInit = 456;
a.fieldWithNoInit = 456;
Expect.equals(1, initCalls);
Expect.equals(456, a.fieldWithInit);
Expect.equals(456, a.fieldWithTrivialInit);
Expect.equals(456, a.fieldWithNullInit);
Expect.equals(456, a.fieldWithNoInit);
Expect.equals(1, initCalls);
initCalls = 0;
for (int i = 0; i < 20; ++i) {
// Late, non-final, with init.
var a = A();
Expect.equals(0, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(123, a.fieldWithTrivialInit);
Expect.equals(null, a.fieldWithNullInit);
Expect.throws(
() => a.fieldWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
Expect.equals(123, a.fieldWithInit);
Expect.equals(123, a.fieldWithTrivialInit);
Expect.equals(null, a.fieldWithNullInit);
Expect.throws(
() => a.fieldWithNoInit, (error) => error is LateInitializationError);
Expect.equals(1, initCalls);
a.fieldWithInit = 456;
a.fieldWithTrivialInit = 456;
a.fieldWithNullInit = 456;
a.fieldWithNoInit = 456;
Expect.equals(1, initCalls);
Expect.equals(456, a.fieldWithInit);
Expect.equals(456, a.fieldWithTrivialInit);
Expect.equals(456, a.fieldWithNullInit);
Expect.equals(456, a.fieldWithNoInit);
Expect.equals(1, initCalls);
initCalls = 0;
// Late, non-final, with init that's pre-empted by setter.
var b = A();
Expect.equals(0, initCalls);
b.fieldWithInit = 456;
Expect.equals(0, initCalls);
Expect.equals(456, b.fieldWithInit);
Expect.equals(0, initCalls);
// Late, non-final, with init that's pre-empted by setter.
var b = A();
Expect.equals(0, initCalls);
b.fieldWithInit = 456;
Expect.equals(0, initCalls);
Expect.equals(456, b.fieldWithInit);
Expect.equals(0, initCalls);
// Late, non-final, with init that's pre-empted by null setter.
var c = A();
Expect.equals(0, initCalls);
c.fieldWithInit = null;
Expect.equals(0, initCalls);
Expect.equals(null, c.fieldWithInit);
Expect.equals(0, initCalls);
// Late, non-final, with init that's pre-empted by null setter.
var c = A();
Expect.equals(0, initCalls);
c.fieldWithInit = null;
Expect.equals(0, initCalls);
Expect.equals(null, c.fieldWithInit);
Expect.equals(0, initCalls);
initCalls = 0;
}
}