[vm/compiler] Elide DebugStepCheck instructions in PRODUCT mode

This improves https://dart-review.googlesource.com/c/sdk/+/99287
by removing DebugStepCheck instructions from unoptimized IL
entirely in PRODUCT mode.

Crash mentioned in https://dart-review.googlesource.com/c/sdk/+/99287/1/runtime/vm/compiler/backend/il_arm.cc#7045
is fixed. Also, this CL adds checks which helped me to debug the crash.

Change-Id: I5452877355876b21d2ce21890626db9e5a59f170
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99421
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/backend/flow_graph_checker.cc b/runtime/vm/compiler/backend/flow_graph_checker.cc
index a07ed6d..3b9481f 100644
--- a/runtime/vm/compiler/backend/flow_graph_checker.cc
+++ b/runtime/vm/compiler/backend/flow_graph_checker.cc
@@ -119,6 +119,7 @@
   }
   // Visit regular instructions.
   Instruction* last = block->last_instruction();
+  ASSERT((last == block) == block->IsGraphEntry());
   Instruction* prev = block;
   ASSERT(prev->previous() == nullptr);
   for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 7ac25ef..d7dc61d 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -7042,7 +7042,9 @@
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-#ifndef PRODUCT
+#ifdef PRODUCT
+  UNREACHABLE();
+#else
   ASSERT(!compiler->is_optimizing());
   __ BranchLinkPatchable(StubCode::DebugStepCheck());
   compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 11779d4..5ba37ca 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -6185,7 +6185,9 @@
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-#ifndef PRODUCT
+#ifdef PRODUCT
+  UNREACHABLE();
+#else
   ASSERT(!compiler->is_optimizing());
   __ BranchLinkPatchable(StubCode::DebugStepCheck());
   compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
diff --git a/runtime/vm/compiler/backend/il_dbc.cc b/runtime/vm/compiler/backend/il_dbc.cc
index 8c7b83b..e75bfef 100644
--- a/runtime/vm/compiler/backend/il_dbc.cc
+++ b/runtime/vm/compiler/backend/il_dbc.cc
@@ -1317,7 +1317,9 @@
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-#ifndef PRODUCT
+#ifdef PRODUCT
+  UNREACHABLE();
+#else
   __ DebugStep();
   compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
 #endif
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 19daf1e..88ce5ba 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -6384,7 +6384,9 @@
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-#ifndef PRODUCT
+#ifdef PRODUCT
+  UNREACHABLE();
+#else
   ASSERT(!compiler->is_optimizing());
   __ Call(StubCode::DebugStepCheck());
   compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index be9b9b6..af182c4 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -6481,7 +6481,9 @@
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-#ifndef PRODUCT
+#ifdef PRODUCT
+  UNREACHABLE();
+#else
   ASSERT(!compiler->is_optimizing());
   __ CallPatchable(StubCode::DebugStepCheck());
   compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 8d34ae8..8a7550f 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -10,6 +10,7 @@
 #include "vm/compiler/aot/precompiler.h"
 #include "vm/compiler/backend/block_scheduler.h"
 #include "vm/compiler/backend/branch_optimizer.h"
+#include "vm/compiler/backend/flow_graph_checker.h"
 #include "vm/compiler/backend/flow_graph_compiler.h"
 #include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/backend/type_propagator.h"
@@ -1062,6 +1063,10 @@
         {
           callee_graph = builder.BuildGraph();
 
+#if defined(DEBUG)
+          FlowGraphChecker(callee_graph).Check();
+#endif
+
           CalleeGraphValidator::Validate(callee_graph);
         }
 #if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_DBC) &&                  \
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 8268034..ba7ab1b 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -1142,8 +1142,12 @@
 }
 
 Fragment FlowGraphBuilder::DebugStepCheck(TokenPosition position) {
+#ifdef PRODUCT
+  return Fragment();
+#else
   return Fragment(new (Z) DebugStepCheckInstr(
       position, RawPcDescriptors::kRuntimeCall, GetNextDeoptId()));
+#endif
 }
 
 Fragment FlowGraphBuilder::EvaluateAssertion() {
@@ -2011,7 +2015,12 @@
   extra_entry += Drop();
   extra_entry += Goto(join_entry);
 
-  join_entry->LinkTo(prologue_start);
+  if (prologue_start != nullptr) {
+    join_entry->LinkTo(prologue_start);
+  } else {
+    // Prologue is empty.
+    shared_prologue_linked_in.current = join_entry;
+  }
 
   TargetEntryInstr *do_checks, *skip_checks;
   shared_prologue_linked_in +=
diff --git a/runtime/vm/compiler/frontend/prologue_builder.cc b/runtime/vm/compiler/frontend/prologue_builder.cc
index deb29dc..f0cb2cf 100644
--- a/runtime/vm/compiler/frontend/prologue_builder.cc
+++ b/runtime/vm/compiler/frontend/prologue_builder.cc
@@ -81,12 +81,13 @@
 
   // Always do this to preserve deoptid numbering.
   JoinEntryInstr* normal_code = BuildJoinEntry();
-  prologue += Goto(normal_code);
+  Fragment jump_to_normal_code = Goto(normal_code);
 
   if (is_empty_prologue) {
     *prologue_info = PrologueInfo(-1, -1);
     return entry;
   } else {
+    prologue += jump_to_normal_code;
     *prologue_info =
         PrologueInfo(previous_block_id, normal_code->block_id() - 1);
     return normal_code;