[vm] Benchmark for reading kernel bytecode

Change-Id: I07617a553193495fcc4fc0ce4a6382996ee7dc51
Reviewed-on: https://dart-review.googlesource.com/75821
Commit-Queue: Zach Anderson <zra@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index c6bb522..ec7e381 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -1149,7 +1149,6 @@
   args = [
     "--gen-bytecode",
     "--no-embed-sources",
-    "--drop-ast",
     "--platform",
     rebase_path(platform_dill),
     "--output",
diff --git a/runtime/include/dart_native_api.h b/runtime/include/dart_native_api.h
index b401d37..9959ef4 100644
--- a/runtime/include/dart_native_api.h
+++ b/runtime/include/dart_native_api.h
@@ -169,6 +169,8 @@
  */
 DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll();
 
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_ReadAllBytecode();
+
 /**
  * Parses all loaded functions in the current isolate..
  *
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 9170ada..459a5a1 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -101,6 +101,7 @@
 cc/Profiler_ContextAllocation: Fail, Pass # Flaky on Windows --- sometimes give "profiler_test.cc: 1107: error: expected: !walker.Down()"
 cc/Service_Profile: Skip
 cc/GenKernelKernelLoadKernel: Skip  # Issue 34542.
+cc/GenKernelKernelReadAllBytecode: Skip  # Issue 34393.
 
 [ !$strong ]
 dart/callee_side_type_checks_test: SkipByDesign
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index e2b2d9a..e699f47 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -178,6 +178,8 @@
   free(script);
 }
 
+#endif  // !PRODUCT
+
 // This file is created by the target //runtime/bin:gen_kernel_bytecode_dill
 // which is depended on by run_vm_tests.
 static char* ComputeGenKernelKernelPath(const char* arg) {
@@ -230,9 +232,47 @@
   int64_t elapsed_time = timer.TotalElapsedTime();
   benchmark->set_score(elapsed_time);
   free(dill_path);
+  free(kernel_buffer);
 }
 
-#endif  // !PRODUCT
+BENCHMARK(GenKernelKernelReadAllBytecode) {
+  bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
+  bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
+  bin::Builtin::SetNativeResolver(bin::Builtin::kCLILibrary);
+  char* dill_path = ComputeGenKernelKernelPath(Benchmark::Executable());
+  File* file = File::Open(NULL, dill_path, File::kRead);
+  EXPECT(file != NULL);
+  bin::RefCntReleaseScope<File> rs(file);
+  intptr_t kernel_buffer_size = file->Length();
+  uint8_t* kernel_buffer =
+      reinterpret_cast<uint8_t*>(malloc(kernel_buffer_size));
+  EXPECT(kernel_buffer != NULL);
+  bool read_fully = file->ReadFully(kernel_buffer, kernel_buffer_size);
+  EXPECT(read_fully);
+
+  bool enable_interpreter_orig = FLAG_enable_interpreter;
+  FLAG_enable_interpreter = true;
+
+  Dart_Handle result =
+      Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size);
+  EXPECT_VALID(result);
+
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
+
+  Timer timer(true, "GenKernelKernelLoadKernel benchmark");
+  timer.Start();
+
+  result = Dart_ReadAllBytecode();
+  EXPECT_VALID(result);
+
+  timer.Stop();
+  int64_t elapsed_time = timer.TotalElapsedTime();
+  benchmark->set_score(elapsed_time);
+  FLAG_enable_interpreter = enable_interpreter_orig;
+  free(dill_path);
+  free(kernel_buffer);
+}
 
 //
 // Measure creation of core isolate from a snapshot.
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index 4695d22..e2e44ad 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -1425,6 +1425,34 @@
   return Error::null();
 }
 
+RawError* Compiler::ReadAllBytecode(const Class& cls) {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
+  ASSERT(error.IsNull());
+  Array& functions = Array::Handle(zone, cls.functions());
+  Function& func = Function::Handle(zone);
+  // Class dynamic lives in the vm isolate. Its array fields cannot be set to
+  // an empty array.
+  if (functions.IsNull()) {
+    ASSERT(cls.IsDynamicClass());
+    return Error::null();
+  }
+  // Compile all the regular functions.
+  for (int i = 0; i < functions.Length(); i++) {
+    func ^= functions.At(i);
+    ASSERT(!func.IsNull());
+    if (func.IsBytecodeAllowed(zone) && !func.HasBytecode()) {
+      RawError* error =
+          kernel::BytecodeReader::ReadFunctionBytecode(thread, func);
+      if (error != Error::null()) {
+        return error;
+      }
+    }
+  }
+  return Error::null();
+}
+
 RawError* Compiler::ParseAllFunctions(const Class& cls) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
diff --git a/runtime/vm/compiler/jit/compiler.h b/runtime/vm/compiler/jit/compiler.h
index 9dc8396..5d5d3bd 100644
--- a/runtime/vm/compiler/jit/compiler.h
+++ b/runtime/vm/compiler/jit/compiler.h
@@ -154,6 +154,9 @@
   static RawError* CompileAllFunctions(const Class& cls);
   static RawError* ParseAllFunctions(const Class& cls);
 
+  // Eagerly read all bytecode.
+  static RawError* ReadAllBytecode(const Class& cls);
+
   // Notify the compiler that background (optimized) compilation has failed
   // because the mutator thread changed the state (e.g., deoptimization,
   // deferred loading). The background compilation may retry to compile
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 5ffbc1b..49cbe58 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -197,6 +197,26 @@
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 }
 
+DART_EXPORT Dart_Handle Dart_ReadAllBytecode() {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  return Api::NewError("%s: Cannot read bytecode on an AOT runtime.",
+                       CURRENT_FUNC);
+#else
+  DARTSCOPE(Thread::Current());
+  API_TIMELINE_DURATION(T);
+  Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
+  if (::Dart_IsError(result)) {
+    return result;
+  }
+  CHECK_CALLBACK_STATE(T);
+  const Error& error = Error::Handle(T->zone(), Library::ReadAllBytecode());
+  if (!error.IsNull()) {
+    return Api::NewHandle(T, error.raw());
+  }
+  return Api::Success();
+#endif  // defined(DART_PRECOMPILED_RUNTIME)
+}
+
 DART_EXPORT Dart_Handle Dart_ParseAll() {
 #if defined(DART_PRECOMPILED_RUNTIME)
   return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index bfccccf..1f464d2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -13,6 +13,7 @@
 #include "vm/compiler/aot/precompiler.h"
 #include "vm/compiler/assembler/assembler.h"
 #include "vm/compiler/assembler/disassembler.h"
+#include "vm/compiler/frontend/bytecode_reader.h"
 #include "vm/compiler/frontend/kernel_fingerprints.h"
 #include "vm/compiler/frontend/kernel_translation_helper.h"
 #include "vm/compiler/intrinsifier.h"
@@ -13321,6 +13322,51 @@
   return Error::null();
 }
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+RawError* Library::ReadAllBytecode() {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Error& error = Error::Handle(zone);
+  const GrowableObjectArray& libs = GrowableObjectArray::Handle(
+      Isolate::Current()->object_store()->libraries());
+  Library& lib = Library::Handle(zone);
+  Class& cls = Class::Handle(zone);
+  for (int i = 0; i < libs.Length(); i++) {
+    lib ^= libs.At(i);
+    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+    while (it.HasNext()) {
+      cls = it.GetNextClass();
+      error = cls.EnsureIsFinalized(thread);
+      if (!error.IsNull()) {
+        return error.raw();
+      }
+      error = Compiler::ReadAllBytecode(cls);
+      if (!error.IsNull()) {
+        return error.raw();
+      }
+    }
+  }
+
+  // Inner functions get added to the closures array. As part of compilation
+  // more closures can be added to the end of the array. Compile all the
+  // closures until we have reached the end of the "worklist".
+  const GrowableObjectArray& closures = GrowableObjectArray::Handle(
+      zone, Isolate::Current()->object_store()->closure_functions());
+  Function& func = Function::Handle(zone);
+  for (int i = 0; i < closures.Length(); i++) {
+    func ^= closures.At(i);
+    if (func.IsBytecodeAllowed(zone) && !func.HasBytecode()) {
+      RawError* error =
+          kernel::BytecodeReader::ReadFunctionBytecode(thread, func);
+      if (error != Error::null()) {
+        return error;
+      }
+    }
+  }
+  return Error::null();
+}
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
 RawError* Library::ParseAll(Thread* thread) {
   Zone* zone = thread->zone();
   Error& error = Error::Handle(zone);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 11a91e3..608c670 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4101,6 +4101,10 @@
   // Eagerly compile all classes and functions in the library.
   static RawError* CompileAll();
   static RawError* ParseAll(Thread* thread);
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  // Eagerly read all bytecode.
+  static RawError* ReadAllBytecode();
+#endif
 
 #if defined(DART_NO_SNAPSHOT)
   // Checks function fingerprints. Prints mismatches and aborts if