[vm, bytecode] Plumb bytecode mode flags to VM unit tests.

 - Make tests using eval fail instead of timing out.
 - Collect allocation stats in the interpreter.
 - And various EnsureDeclarationLoaded.

Change-Id: I17377216cd6dde2615b205f1b28071e12e50e252
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107442
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart
index 5883b16..618a023 100644
--- a/pkg/test_runner/lib/src/test_suite.dart
+++ b/pkg/test_runner/lib/src/test_suite.dart
@@ -370,6 +370,7 @@
       var dfePath = Path(filename).absolute.toNativePath();
       // '--dfe' has to be the first argument for run_vm_test to pick it up.
       args.insert(0, '--dfe=$dfePath');
+      args.addAll(configuration.vmOptions);
     }
     if (expectations.contains(Expectation.crash)) {
       args.insert(0, '--suppress-core-dump');
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 2ad49bc..9d6e345 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -534,7 +534,12 @@
     assert(incremental,
         "Incremental compiler required for use of 'kUpdateSourcesTag'");
     compiler = lookupIncrementalCompiler(isolateId);
-    assert(compiler != null);
+    if (compiler == null) {
+      port.send(new CompilationResult.errors(
+              ["No incremental compiler available for this isolate."], null)
+          .toResponse());
+      return;
+    }
     updateSources(compiler, sourceFiles);
     port.send(new CompilationResult.ok(null).toResponse());
     return;
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 30938b5..03475ab 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -35,7 +35,7 @@
 dart/entrypoints/aot/*: SkipByDesign
 
 [ $compiler == dartkb ]
-cc/*: Skip # Bytecode modes are not properly hooked up in run_vm_tests.
+cc/*: Skip # Too many timeouts and crashes for infrastructure to handle.
 
 [ $compiler == dartkp ]
 dart/v8_snapshot_profile_writer_test: Pass, Slow # Can be slow due to re-invoking the precompiler.
diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc
index a219c2a..1e56f5a 100644
--- a/runtime/vm/compiler/backend/il_test_helper.cc
+++ b/runtime/vm/compiler/backend/il_test_helper.cc
@@ -45,6 +45,10 @@
 }
 
 void Invoke(const Library& lib, const char* name) {
+  // These tests rely on running unoptimized code to collect type feedback. The
+  // interpreter does not collect type feedback for interface calls.
+  SetFlagScope<bool> sfs(&FLAG_enable_interpreter, false);
+
   Thread* thread = Thread::Current();
   Dart_Handle api_lib = Api::NewHandle(thread, lib.raw());
   TransitionVMToNative transition(thread);
diff --git a/runtime/vm/compiler/backend/loops_test.cc b/runtime/vm/compiler/backend/loops_test.cc
index 4b208f8..b2b2e23 100644
--- a/runtime/vm/compiler/backend/loops_test.cc
+++ b/runtime/vm/compiler/backend/loops_test.cc
@@ -307,7 +307,7 @@
       "  WRAP(-99, LIN(0 + -1 * i))\n"  // d
       "  LIN(1 + 1 * i)\n"              // add
       "  ]\n";
-  EXPECT_STREQ(ComputeInduction(thread, script_chars), expected);
+  EXPECT_STREQ(expected, ComputeInduction(thread, script_chars));
 }
 
 ISOLATE_UNIT_TEST_CASE(PeriodicAndDerived) {
@@ -342,7 +342,7 @@
       "  PERIOD(95, 5)\n"       // p2
       "  LIN(1 + 1 * i)\n"      // add
       "  ]\n";
-  EXPECT_STREQ(ComputeInduction(thread, script_chars), expected);
+  EXPECT_STREQ(expected, ComputeInduction(thread, script_chars));
 }
 
 //
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 5a9c5b6..35306a3 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -5106,6 +5106,7 @@
     return Api::NewError("Class '%s' not found in library '%s'.",
                          cls_name.ToCString(), lib_name.ToCString());
   }
+  cls.EnsureDeclarationLoaded();
   CHECK_ERROR_HANDLE(cls.VerifyEntryPoint());
   return Api::NewHandle(T, cls.RareType());
 }
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 3b58a09..cf801d2c 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -1355,6 +1355,8 @@
   const uword start = thread->top();
   if (LIKELY((start + instance_size) < thread->end())) {
     thread->set_top(start + instance_size);
+    NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+        kMintCid, instance_size));
     RawMint* result =
         Mint::RawCast(InitializeHeader(start, kMintCid, instance_size));
     result->ptr()->value_ = value;
@@ -1385,6 +1387,8 @@
   const uword start = thread->top();
   if (LIKELY((start + instance_size) < thread->end())) {
     thread->set_top(start + instance_size);
+    NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+        kDoubleCid, instance_size));
     RawDouble* result =
         Double::RawCast(InitializeHeader(start, kDoubleCid, instance_size));
     result->ptr()->value_ = value;
@@ -1415,6 +1419,8 @@
   const uword start = thread->top();
   if (LIKELY((start + instance_size) < thread->end())) {
     thread->set_top(start + instance_size);
+    NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+        kFloat32x4Cid, instance_size));
     RawFloat32x4* result = Float32x4::RawCast(
         InitializeHeader(start, kFloat32x4Cid, instance_size));
     value.writeTo(result->ptr()->value_);
@@ -1445,6 +1451,8 @@
   const uword start = thread->top();
   if (LIKELY((start + instance_size) < thread->end())) {
     thread->set_top(start + instance_size);
+    NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+        kFloat64x2Cid, instance_size));
     RawFloat64x2* result = Float64x2::RawCast(
         InitializeHeader(start, kFloat64x2Cid, instance_size));
     value.writeTo(result->ptr()->value_);
@@ -1479,6 +1487,8 @@
       const uword start = thread->top();
       if (LIKELY((start + instance_size) < thread->end())) {
         thread->set_top(start + instance_size);
+        NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+            kArrayCid, instance_size));
         RawArray* result =
             Array::RawCast(InitializeHeader(start, kArrayCid, instance_size));
         result->ptr()->type_arguments_ = type_args;
@@ -1512,6 +1522,8 @@
   const uword start = thread->top();
   if (LIKELY((start + instance_size) < thread->end())) {
     thread->set_top(start + instance_size);
+    NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+        kContextCid, instance_size));
     RawContext* result =
         Context::RawCast(InitializeHeader(start, kContextCid, instance_size));
     result->ptr()->num_variables_ = num_context_variables;
@@ -1542,6 +1554,8 @@
   const uword start = thread->top();
   if (LIKELY((start + instance_size) < thread->end())) {
     thread->set_top(start + instance_size);
+    NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+        kClosureCid, instance_size));
     RawClosure* result =
         Closure::RawCast(InitializeHeader(start, kClosureCid, instance_size));
     RawObject* null_value = Object::null();
@@ -2481,6 +2495,8 @@
       const uword start = thread->top();
       if (LIKELY((start + instance_size) < thread->end())) {
         thread->set_top(start + instance_size);
+        NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+            class_id, instance_size));
         RawObject* result = InitializeHeader(start, class_id, instance_size);
         for (intptr_t offset = sizeof(RawInstance); offset < instance_size;
              offset += kWordSize) {
@@ -2512,6 +2528,8 @@
       const uword start = thread->top();
       if (LIKELY((start + instance_size) < thread->end())) {
         thread->set_top(start + instance_size);
+        NOT_IN_PRODUCT(thread->isolate()->class_table()->UpdateAllocatedNew(
+            class_id, instance_size));
         RawObject* result = InitializeHeader(start, class_id, instance_size);
         for (intptr_t offset = sizeof(RawInstance); offset < instance_size;
              offset += kWordSize) {
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 215e311..b084d5d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2276,6 +2276,7 @@
 }
 
 RawAbstractType* Class::RareType() const {
+  ASSERT(is_declaration_loaded());
   const Type& type = Type::Handle(Type::New(
       *this, Object::null_type_arguments(), TokenPosition::kNoSource));
   return ClassFinalizer::FinalizeType(*this, type);
@@ -4152,6 +4153,7 @@
 }
 
 RawType* Class::DeclarationType() const {
+  ASSERT(is_declaration_loaded());
   if (declaration_type() != Type::null()) {
     return declaration_type();
   }
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index 860b4a65..0a79bd9 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -569,6 +569,7 @@
         }
         ASSERT(cls.is_finalized());
       } else {
+        cls.EnsureDeclarationLoaded();
         // Emit one range for the whole uncompiled class.
         JSONObject range(jsarr);
         script = cls.script();
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index fa77c7d..3f25010 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -48,7 +48,7 @@
   if (!expected.OperatorEquals(actual)) {
     OS::PrintErr("expected: '%s' actual: '%s'\n", expected.ToCString(),
                  actual.ToCString());
-    FATAL("Expect_equals fails.\n");
+    EXPECT(false);
   }
 }
 
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index b75e93b..d7a6e3c 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -676,7 +676,7 @@
             String::Handle(lib.url()).ToCString(), /* klass=*/nullptr,
             /* is_static= */ false);
     if (compilation_result.status != Dart_KernelCompilationStatus_Ok) {
-      return Dart_NewApiError(compilation_result.error);
+      return Api::NewError("%s", compilation_result.error);
     }
 
     const uint8_t* kernel_bytes = compilation_result.kernel;