[vm/compiler] Do not generate unnecessary field length guards

GuardFieldLengthInstr::EmitNativeCode aborts background compilation
if we're not tracking list length for a field
(guarded_list_length() == Field::kNoFixedLength).
I'm seeing a lot of aborted background compilations on a Flutter app with
the reason "GuardFieldLengthInstr: field state changed while compiling".

This CL avoids generating these useless (and harmful) GuardFieldLengthInstr
if not tracking list length for a field.

Change-Id: I2a083c5df35e89893c9e787bebe4e3e7d8177c83
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99737
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Aart Bik <ajcbik@google.com>
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index 07ac0b0..aff93f9 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -485,8 +485,19 @@
     LocalVariable* store_expression = MakeTemporary();
     instructions += LoadLocal(store_expression);
     instructions += GuardFieldClass(field_clone, GetNextDeoptId());
-    instructions += LoadLocal(store_expression);
-    instructions += GuardFieldLength(field_clone, GetNextDeoptId());
+
+    // Field length guard can be omitted if it is not needed.
+    // However, it is possible that we were tracking list length previously,
+    // and generated length guards in the past. We need to generate same IL
+    // to keep deopt ids stable, but we can discard generated IL fragment
+    // if length guard is not needed.
+    Fragment length_guard;
+    length_guard += LoadLocal(store_expression);
+    length_guard += GuardFieldLength(field_clone, GetNextDeoptId());
+
+    if (field_clone.needs_length_check()) {
+      instructions += length_guard;
+    }
 
     // If we are tracking exactness of the static type of the field then
     // emit appropriate guard.