mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:43:57 +00:00
[vm] Treat static final fields with trivial initializers as const
When loading a value of a static final field with trivial initializer generate a Constant instruction instead of LoadStaticField. Initializer of a static field is considered trivial if it is null, int, double, String or bool literal. TEST=vm/cc/StreamingFlowGraphBuilder_StaticGetFinalFieldWithTrivialInitializer Fixes https://github.com/dart-lang/sdk/issues/47120 Change-Id: Id2bfc3da8c14376f7f1ef829265cca29a018bad1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212873 Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
1d6f4c742f
commit
30abce99f3
|
@ -552,7 +552,7 @@ ISOLATE_UNIT_TEST_CASE(TypePropagator_NonNullableLoadStaticField) {
|
|||
|
||||
const char* kScript = R"(
|
||||
const y = 0xDEADBEEF;
|
||||
final int x = 0xFEEDFEED;
|
||||
final int x = int.parse('0xFEEDFEED');
|
||||
|
||||
void main(List<String> args) {
|
||||
print(x);
|
||||
|
|
|
@ -2776,6 +2776,10 @@ Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
|
|||
Class::Handle(field.Owner()).Name() == Symbols::ClassID().ptr());
|
||||
return Constant(Instance::ZoneHandle(
|
||||
Z, Instance::RawCast(field.StaticConstFieldValue())));
|
||||
} else if (field.is_final() && field.has_trivial_initializer()) {
|
||||
// Final fields with trivial initializers are effectively constant.
|
||||
return Constant(Instance::ZoneHandle(
|
||||
Z, Instance::RawCast(field.StaticConstFieldValue())));
|
||||
} else {
|
||||
const Class& owner = Class::Handle(Z, field.Owner());
|
||||
const String& getter_name = H.DartGetterName(target);
|
||||
|
|
|
@ -340,4 +340,44 @@ ISOLATE_UNIT_TEST_CASE(StreamingFlowGraphBuilder_TypedClosureCall) {
|
|||
// clang-format on
|
||||
}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(
|
||||
StreamingFlowGraphBuilder_StaticGetFinalFieldWithTrivialInitializer) {
|
||||
const char* kScript = R"(
|
||||
final int x = 0xFEEDFEED;
|
||||
test() {
|
||||
return x;
|
||||
}
|
||||
)";
|
||||
|
||||
const auto& root_library = Library::Handle(LoadTestScript(kScript));
|
||||
const auto& function = Function::Handle(GetFunction(root_library, "test"));
|
||||
|
||||
Invoke(root_library, "test");
|
||||
|
||||
TestPipeline pipeline(function, CompilerPass::kJIT);
|
||||
FlowGraph* flow_graph = pipeline.RunPasses({
|
||||
CompilerPass::kComputeSSA,
|
||||
});
|
||||
|
||||
auto entry = flow_graph->graph_entry()->normal_entry();
|
||||
EXPECT(entry != nullptr);
|
||||
|
||||
ReturnInstr* return_instr = nullptr;
|
||||
|
||||
ILMatcher cursor(flow_graph, entry);
|
||||
RELEASE_ASSERT(cursor.TryMatch({
|
||||
kMatchAndMoveFunctionEntry,
|
||||
kMatchAndMoveCheckStackOverflow,
|
||||
kMoveDebugStepChecks,
|
||||
{kMatchReturn, &return_instr},
|
||||
}));
|
||||
|
||||
EXPECT(return_instr != nullptr);
|
||||
ConstantInstr* const_value =
|
||||
return_instr->value()->definition()->AsConstant();
|
||||
EXPECT(const_value != nullptr);
|
||||
EXPECT(const_value->value().IsInteger());
|
||||
EXPECT_EQ(0xFEEDFEED, Integer::Cast(const_value->value()).AsInt64Value());
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -881,7 +881,8 @@ void KernelLoader::CheckForInitializer(const Field& field) {
|
|||
SimpleExpressionConverter converter(&H, &helper_);
|
||||
const bool has_simple_initializer =
|
||||
converter.IsSimple(helper_.ReaderOffset() + 1);
|
||||
if (!has_simple_initializer || !converter.SimpleValue().IsNull()) {
|
||||
if (!has_simple_initializer ||
|
||||
(!field.is_static() && !converter.SimpleValue().IsNull())) {
|
||||
field.set_has_nontrivial_initializer(true);
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -11172,7 +11172,8 @@ ErrorPtr Field::InitializeStatic() const {
|
|||
}
|
||||
|
||||
ObjectPtr Field::StaticConstFieldValue() const {
|
||||
ASSERT(is_static() && is_const());
|
||||
ASSERT(is_static() &&
|
||||
(is_const() || (is_final() && has_trivial_initializer())));
|
||||
|
||||
auto thread = Thread::Current();
|
||||
auto zone = thread->zone();
|
||||
|
@ -11183,7 +11184,11 @@ ObjectPtr Field::StaticConstFieldValue() const {
|
|||
auto& value = Object::Handle(
|
||||
zone, initial_field_table->At(field_id(), /*concurrent_use=*/true));
|
||||
if (value.ptr() == Object::sentinel().ptr()) {
|
||||
// Fields with trivial initializers get their initial value
|
||||
// eagerly when they are registered.
|
||||
ASSERT(is_const());
|
||||
ASSERT(has_initializer());
|
||||
ASSERT(has_nontrivial_initializer());
|
||||
value = EvaluateInitializer();
|
||||
if (!value.IsError()) {
|
||||
ASSERT(value.IsNull() || value.IsInstance());
|
||||
|
|
Loading…
Reference in a new issue