Revert "[vm/compiler] Improved type analysis for check class."

This reverts commit 5333dd7f0f82faa03cbade6556f1b9b9eb2421ea.

Reason for revert:

vm-kernel-optcounter-threshold-linux-release-x64
started to timeout on buildbot, see:

https://github.com/dart-lang/sdk/issues/33870

Original change's description:
> [vm/compiler] Improved type analysis for check class.
> 
> Rationale:
> Improves the analysis if instance calls need checks
> (check class or check null) combined with CHA.
> 
> Bug: https://github.com/dart-lang/sdk/issues/33664
> 
> 
> Change-Id: I0a4761f8816bf5a5aaf5d17ca56d8bf4e3b79fc3
> Reviewed-on: https://dart-review.googlesource.com/64440
> Commit-Queue: Aart Bik <ajcbik@google.com>
> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
> Reviewed-by: Alexander Markov <alexmarkov@google.com>

TBR=vegorov@google.com,alexmarkov@google.com,asiva@google.com,ajcbik@google.com

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: https://github.com/dart-lang/sdk/issues/33664
Change-Id: Iac1e630e55ffbbb0b635c28bbfd5211c2ae6751d
Reviewed-on: https://dart-review.googlesource.com/65220
Reviewed-by: Aart Bik <ajcbik@google.com>
Commit-Queue: Aart Bik <ajcbik@google.com>
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index b41ad00..93bcf21bf 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -800,8 +800,7 @@
   if (has_one_target) {
     RawFunction::Kind function_kind =
         Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
-    if (flow_graph()->CheckForInstanceCall(instr, function_kind) ==
-        FlowGraph::ToCheck::kNoCheck) {
+    if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
       CallTargets* targets = CallTargets::Create(Z, unary_checks);
       ASSERT(targets->HasSingleTarget());
       const Function& target = targets->FirstTarget();
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 02d00b3..1f079f6 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -15,7 +15,6 @@
 #include "vm/compiler/frontend/flow_graph_builder.h"
 #include "vm/growable_array.h"
 #include "vm/object_store.h"
-#include "vm/resolver.h"
 
 namespace dart {
 
@@ -417,91 +416,38 @@
   return (phi->is_receiver() == PhiInstr::kReceiver);
 }
 
-FlowGraph::ToCheck FlowGraph::CheckForInstanceCall(
-    InstanceCallInstr* call,
-    RawFunction::Kind kind) const {
+// Use CHA to determine if the call needs a class check: if the callee's
+// receiver is the same as the caller's receiver and there are no overridden
+// callee functions, then no class check is needed.
+bool FlowGraph::InstanceCallNeedsClassCheck(InstanceCallInstr* call,
+                                            RawFunction::Kind kind) const {
   if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) {
     // Even if class or function are private, lazy class finalization
     // may later add overriding methods.
-    return ToCheck::kCheckCid;
+    return true;
   }
-
-  // Best effort to get the receiver class.
-  Value* receiver = call->Receiver();
-  Class& receiver_class = Class::Handle(zone());
-  bool receiver_maybe_null = false;
-  if (function().IsDynamicFunction() && IsReceiver(receiver->definition())) {
-    // Call receiver is callee receiver: calling "this.g()" in f().
-    receiver_class = function().Owner();
-  } else if (FLAG_use_strong_mode_types && isolate()->strong()) {
-    // In strong mode, get the receiver's compile type. Note that
-    // we allow nullable types, which may result in just generating
-    // a null check rather than the more elaborate class check
-    CompileType* type = receiver->Type();
-    const AbstractType* atype = type->ToAbstractType();
-    if (atype->HasResolvedTypeClass() && !atype->IsDynamicType()) {
-      if (type->is_nullable()) {
-        receiver_maybe_null = true;
+  Definition* callee_receiver = call->Receiver()->definition();
+  ASSERT(callee_receiver != NULL);
+  if (function().IsDynamicFunction() && IsReceiver(callee_receiver)) {
+    const String& name =
+        (kind == RawFunction::kMethodExtractor)
+            ? String::Handle(zone(),
+                             Field::NameFromGetter(call->function_name()))
+            : call->function_name();
+    const Class& cls = Class::Handle(zone(), function().Owner());
+    intptr_t subclass_count = 0;
+    if (!thread()->cha()->HasOverride(cls, name, &subclass_count)) {
+      if (FLAG_trace_cha) {
+        THR_Print(
+            "  **(CHA) Instance call needs no check, "
+            "no overrides of '%s' '%s'\n",
+            name.ToCString(), cls.ToCString());
       }
-      receiver_class = atype->type_class();
-      if (receiver_class.is_implemented()) {
-        receiver_class = Class::null();
-      }
+      thread()->cha()->AddToGuardedClasses(cls, subclass_count);
+      return false;
     }
   }
-
-  // Useful receiver class information?
-  if (receiver_class.IsNull()) {
-    return ToCheck::kCheckCid;
-  } else if (FLAG_precompiled_mode && call->HasICData() &&
-             !call->ic_data()->HasReceiverClassId(receiver_class.id())) {
-    // In AOT, if the static class type does not match information
-    // found in ICData (which may be "guessed"), then bail, since
-    // subsequent code generation for inlining uses the latter.
-    // TODO(ajcbik): improve this by using the static class in AOT.
-    return ToCheck::kCheckCid;
-  }
-
-  const String& method_name =
-      (kind == RawFunction::kMethodExtractor)
-          ? String::Handle(zone(), Field::NameFromGetter(call->function_name()))
-          : call->function_name();
-
-  // If the receiver can have the null value, exclude any method
-  // that is actually valid on a null receiver.
-  if (receiver_maybe_null) {
-#ifdef TARGET_ARCH_DBC
-    // TODO(ajcbik): DBC does not support null check at all yet.
-    return ToCheck::kCheckCid;
-#else
-    const Class& null_class =
-        Class::Handle(zone(), isolate()->object_store()->null_class());
-    const Function& target = Function::Handle(
-        zone(),
-        Resolver::ResolveDynamicAnyArgs(zone(), null_class, method_name));
-    if (!target.IsNull()) {
-      return ToCheck::kCheckCid;
-    }
-#endif
-  }
-
-  // Use CHA to determine if the method is not overridden by any subclass
-  // of the receiver class. Any methods that are valid when the receiver
-  // has a null value are excluded above (to avoid throwing an exception
-  // on something valid, like null.hashCode).
-  intptr_t subclass_count = 0;
-  if (!thread()->cha()->HasOverride(receiver_class, method_name,
-                                    &subclass_count)) {
-    if (FLAG_trace_cha) {
-      THR_Print(
-          "  **(CHA) Instance call needs no class check since there "
-          "are no overrides of method '%s' on '%s'\n",
-          method_name.ToCString(), receiver_class.ToCString());
-    }
-    thread()->cha()->AddToGuardedClasses(receiver_class, subclass_count);
-    return receiver_maybe_null ? ToCheck::kCheckNull : ToCheck::kNoCheck;
-  }
-  return ToCheck::kCheckCid;
+  return true;
 }
 
 Instruction* FlowGraph::CreateCheckClass(Definition* to_check,
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index 4a8e86c..a583585 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -183,13 +183,8 @@
     return current_ssa_temp_index();
   }
 
-  enum class ToCheck { kNoCheck, kCheckNull, kCheckCid };
-
-  // Uses CHA to determine if the called method can be overridden.
-  // Return value indicates that the call needs no check at all,
-  // just a null check, or a full class check.
-  ToCheck CheckForInstanceCall(InstanceCallInstr* call,
-                               RawFunction::Kind kind) const;
+  bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
+                                   RawFunction::Kind kind) const;
 
   Thread* thread() const { return thread_; }
   Zone* zone() const { return thread()->zone(); }
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 07c8847..f041b41 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -3117,35 +3117,13 @@
           flow_graph, receiver_cid, target, call,
           call->Receiver()->definition(), call->token_pos(), call->ic_data(),
           &entry, &last, policy)) {
-    // Determine if inlining instance methods needs a check.
-    FlowGraph::ToCheck check = FlowGraph::ToCheck::kNoCheck;
-    if (MethodRecognizer::PolymorphicTarget(target)) {
-      check = FlowGraph::ToCheck::kCheckCid;
-    } else {
-      check = flow_graph->CheckForInstanceCall(call, target.kind());
-    }
-
-    // Insert receiver class or null check if needed.
-    switch (check) {
-      case FlowGraph::ToCheck::kCheckCid: {
-        Instruction* check_class =
-            flow_graph->CreateCheckClass(call->Receiver()->definition(),
-                                         *Cids::Create(Z, *call->ic_data(), 0),
-                                         call->deopt_id(), call->token_pos());
-        flow_graph->InsertBefore(call, check_class, call->env(),
-                                 FlowGraph::kEffect);
-        break;
-      }
-      case FlowGraph::ToCheck::kCheckNull: {
-        Instruction* check_null = new (Z) CheckNullInstr(
-            call->Receiver()->CopyWithType(Z), call->function_name(),
-            call->deopt_id(), call->token_pos());
-        flow_graph->InsertBefore(call, check_null, call->env(),
-                                 FlowGraph::kEffect);
-        break;
-      }
-      case FlowGraph::ToCheck::kNoCheck:
-        break;
+    // Insert receiver class check if needed.
+    if (MethodRecognizer::PolymorphicTarget(target) ||
+        flow_graph->InstanceCallNeedsClassCheck(call, target.kind())) {
+      Instruction* check = flow_graph->CreateCheckClass(
+          call->Receiver()->definition(), *Cids::Create(Z, *call->ic_data(), 0),
+          call->deopt_id(), call->token_pos());
+      flow_graph->InsertBefore(call, check, call->env(), FlowGraph::kEffect);
     }
 
     // Remove the original push arguments.
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 38c4791..e6b1481 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -879,20 +879,13 @@
   const Field& field = Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
   ASSERT(!field.IsNull());
 
-  switch (
-      flow_graph()->CheckForInstanceCall(call, RawFunction::kImplicitGetter)) {
-    case FlowGraph::ToCheck::kCheckNull:
-      AddCheckNull(call->Receiver(), call->function_name(), call->deopt_id(),
-                   call->env(), call);
-      break;
-    case FlowGraph::ToCheck::kCheckCid:
-      if (FLAG_precompiled_mode) {
-        return false;  // AOT cannot class check
-      }
-      AddReceiverCheck(call);
-      break;
-    case FlowGraph::ToCheck::kNoCheck:
-      break;
+  if (flow_graph()->InstanceCallNeedsClassCheck(call,
+                                                RawFunction::kImplicitGetter)) {
+    if (FLAG_precompiled_mode) {
+      return false;
+    }
+
+    AddReceiverCheck(call);
   }
   InlineImplicitInstanceGetter(call, field);
   return true;
@@ -949,20 +942,13 @@
   const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name));
   ASSERT(!field.IsNull());
 
-  switch (
-      flow_graph()->CheckForInstanceCall(instr, RawFunction::kImplicitSetter)) {
-    case FlowGraph::ToCheck::kCheckNull:
-      AddCheckNull(instr->Receiver(), instr->function_name(), instr->deopt_id(),
-                   instr->env(), instr);
-      break;
-    case FlowGraph::ToCheck::kCheckCid:
-      if (FLAG_precompiled_mode) {
-        return false;  // AOT cannot class check
-      }
-      AddReceiverCheck(instr);
-      break;
-    case FlowGraph::ToCheck::kNoCheck:
-      break;
+  if (flow_graph()->InstanceCallNeedsClassCheck(instr,
+                                                RawFunction::kImplicitSetter)) {
+    if (FLAG_precompiled_mode) {
+      return false;
+    }
+
+    AddReceiverCheck(instr);
   }
 
   if (I->use_field_guards()) {
diff --git a/runtime/vm/compiler/jit/jit_call_specializer.cc b/runtime/vm/compiler/jit/jit_call_specializer.cc
index aabe9ac..fa0ae29 100644
--- a/runtime/vm/compiler/jit/jit_call_specializer.cc
+++ b/runtime/vm/compiler/jit/jit_call_specializer.cc
@@ -132,8 +132,8 @@
   if (has_one_target) {
     const Function& target =
         Function::ZoneHandle(Z, unary_checks.GetTargetAt(0));
-    if (flow_graph()->CheckForInstanceCall(instr, target.kind()) ==
-        FlowGraph::ToCheck::kNoCheck) {
+    const RawFunction::Kind function_kind = target.kind();
+    if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
       StaticCallInstr* call = StaticCallInstr::FromCall(Z, instr, target);
       instr->ReplaceWith(call, current_iterator());
       return;
diff --git a/tests/standalone_2/check_class_cha_test.dart b/tests/standalone_2/check_class_cha_test.dart
deleted file mode 100644
index 19ed029..0000000
--- a/tests/standalone_2/check_class_cha_test.dart
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "package:expect/expect.dart";
-
-// Class hierarchy on an abstract class
-// that defines a "next" structure.
-
-abstract class A {
-  A next;
-}
-
-class B extends A {
-  B(A n) {
-    this.next = n;
-  }
-}
-
-// Method that counts length of list.
-// With only Bs, the getter can be
-// inlined without check class.
-int countMe(A i) {
-  int x = 0;
-  while (i != null) {
-    A next = i.next;
-    x++;
-    i = next;
-  }
-  return x;
-}
-
-int doitHot(A a) {
-  // Warm up the JIT.
-  int d = 0;
-  for (int i = 0; i < 1000; i++) {
-    d += countMe(a);
-  }
-  return d;
-}
-
-// Nasty class that overrides the getter.
-class C extends A {
-  C(A n) {
-    this.next = n;
-  }
-  // New override.
-  A get next => null;
-}
-
-int bringInC(A a) {
-  // Introduce C to compiler.
-  a = new C(a);
-  return doitHot(a);
-}
-
-main() {
-  // Make a list with just Bs.
-  A a = null;
-  for (int i = 0; i < 1000; i++) {
-    a = new B(a);
-  }
-
-  Expect.equals(1000 * 1000, doitHot(a));
-  Expect.equals(1000, bringInC(a));
-}
diff --git a/tests/standalone_2/check_null_cha_test.dart b/tests/standalone_2/check_null_cha_test.dart
deleted file mode 100644
index fc9c17d..0000000
--- a/tests/standalone_2/check_null_cha_test.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "package:expect/expect.dart";
-
-// A class the has a getter also provided by Object
-// (higher in the class hierarchy) and thus also the
-// Null class (besides X in the class hierarchy).
-class X {
-  int hashCode;
-  X() {
-    hashCode = 1;
-  }
-}
-
-// Use this getter on X receiver.
-int hashMe(X x) {
-  int d = 0;
-  for (int i = 0; i < 10; i++) {
-    d += x.hashCode;
-  }
-  return d;
-}
-
-// Use this getter on Null class receiver.
-// Only possible value is null.
-int hashNull(Null x) {
-  int d = 0;
-  for (int i = 0; i < 10; i++) {
-    d += x.hashCode;
-  }
-  return d;
-}
-
-main() {
-  // Warm up the JIT with just an X object. Having a single receiver
-  // of type X with nothing below in the hierarchy that overrides
-  // hashCode could tempt the JIT to inline the getter with CHA
-  // that deopts when X is subclassed in the future.
-  X x = new X();
-  for (int i = 0; i < 1000; i++) {
-    Expect.equals(10, hashMe(x));
-  }
-
-  // However, this is a special case that also works on null
-  // (calling Object's hashCode). So this should not throw an
-  // exception. Had we inlined, this would have hit the null
-  // check and thrown an exception.
-  Expect.notEquals(0, hashMe(null));
-
-  // Also warm up the JIT on a direct Null receiver.
-  int d = 0;
-  for (int i = 0; i < 1000; i++) {
-    d += hashNull(null);
-  }
-  Expect.notEquals(0, d);
-}