[vm/embedder] Introduce dart_standalone_embedder_api.h

This enables other emdedders to reuse parts of the standalone embedder
implementation without depending too much on the implementations details.

As part of the change we also remove a dependency from DartUtils on
IsolateData - by removing dart:_builtin library caching. Lookup
of this library does not seem to be on hot path anymore in Kernel world.

Change-Id: Ia35b28886121828fad7a96f00bcbceff75e00ae8
Reviewed-on: https://dart-review.googlesource.com/64848
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 7f55d9a..5cd4241 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -929,6 +929,7 @@
     }
 
     sources = [
+                "dart_embedder_api_impl.cc",
                 "error_exit.cc",
                 "error_exit.h",
                 "main.cc",
diff --git a/runtime/bin/dart_embedder_api_impl.cc b/runtime/bin/dart_embedder_api_impl.cc
new file mode 100644
index 0000000..645a7bb
--- /dev/null
+++ b/runtime/bin/dart_embedder_api_impl.cc
@@ -0,0 +1,106 @@
+// 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.
+
+#include "include/dart_embedder_api.h"
+
+#include "bin/dartutils.h"
+#include "bin/eventhandler.h"
+#include "bin/isolate_data.h"
+#include "bin/thread.h"
+#include "bin/utils.h"
+#include "bin/vmservice_impl.h"
+
+namespace dart {
+namespace embedder {
+
+static char* MallocFormatedString(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  intptr_t len = vsnprintf(NULL, 0, format, args);
+  va_end(args);
+
+  char* buffer = reinterpret_cast<char*>(malloc(len + 1));
+  MSAN_UNPOISON(buffer, (len + 1));
+  va_list args2;
+  va_start(args2, format);
+  vsnprintf(buffer, (len + 1), format, args2);
+  va_end(args2);
+  return buffer;
+}
+
+bool InitOnce(char** error) {
+  if (!bin::DartUtils::SetOriginalWorkingDirectory()) {
+    bin::OSError err;
+    *error = MallocFormatedString("Error determining current directory: %s\n",
+                                  err.message());
+    return false;
+  }
+  bin::Thread::InitOnce();
+  bin::TimerUtils::InitOnce();
+  bin::EventHandler::Start();
+  return true;
+}
+
+Dart_Isolate CreateKernelServiceIsolate(const IsolateCreationData& data,
+                                        const uint8_t* buffer,
+                                        intptr_t buffer_size,
+                                        char** error) {
+  Dart_Isolate kernel_isolate = Dart_CreateIsolateFromKernel(
+      data.script_uri, data.main, buffer, buffer_size, data.flags,
+      data.callback_data, error);
+  if (kernel_isolate == nullptr) {
+    return nullptr;
+  }
+
+  Dart_EnterScope();
+  Dart_Handle result = Dart_LoadScriptFromKernel(buffer, buffer_size);
+  if (Dart_IsError(result)) {
+    *error = strdup(Dart_GetError(result));
+    Dart_ExitScope();
+    Dart_ShutdownIsolate();
+    return nullptr;
+  }
+  result = bin::DartUtils::PrepareForScriptLoading(/*is_service_isolate=*/false,
+                                                   /*trace_loading=*/false);
+  Dart_ExitScope();
+  Dart_ExitIsolate();
+  return kernel_isolate;
+}
+
+Dart_Isolate CreateVmServiceIsolate(const IsolateCreationData& data,
+                                    const VmServiceConfiguration& config,
+                                    const uint8_t* kernel_buffer,
+                                    intptr_t kernel_buffer_size,
+                                    char** error) {
+  if (data.flags == nullptr) {
+    *error = strdup("Expected non-null flags");
+    return nullptr;
+  }
+  data.flags->load_vmservice_library = true;
+
+  Dart_Isolate service_isolate = Dart_CreateIsolateFromKernel(
+      data.script_uri, data.main, kernel_buffer, kernel_buffer_size, data.flags,
+      data.callback_data, error);
+  if (service_isolate == nullptr) {
+    return nullptr;
+  }
+
+  Dart_EnterScope();
+  // Load embedder specific bits and return.
+  if (!bin::VmService::Setup(config.ip, config.port,
+                             /*running_precompiled=*/true, config.dev_mode,
+                             /*trace_loading=*/false, config.deterministic)) {
+    *error = strdup(bin::VmService::GetErrorMessage());
+    Dart_ExitScope();
+    Dart_ShutdownIsolate();
+    return nullptr;
+  }
+
+  Dart_ExitScope();
+  Dart_ExitIsolate();
+  return service_isolate;
+}
+
+}  // namespace embedder
+}  // namespace dart
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index e7c7886..6bba557 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -385,18 +385,16 @@
 }
 
 Dart_Handle DartUtils::SetWorkingDirectory() {
-  IsolateData* isolate_data =
-      reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
-  Dart_Handle builtin_lib = isolate_data->builtin_lib();
   Dart_Handle directory = NewString(original_working_directory);
-  return SingleArgDart_Invoke(builtin_lib, "_setWorkingDirectory", directory);
+  return SingleArgDart_Invoke(LookupBuiltinLib(), "_setWorkingDirectory",
+                              directory);
 }
 
 Dart_Handle DartUtils::ResolveUriInWorkingDirectory(Dart_Handle script_uri) {
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = script_uri;
-  return Dart_Invoke(DartUtils::BuiltinLib(),
+  return Dart_Invoke(DartUtils::LookupBuiltinLib(),
                      NewString("_resolveInWorkingDirectory"), kNumArgs,
                      dart_args);
 }
@@ -405,16 +403,16 @@
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = library_uri;
-  return Dart_Invoke(DartUtils::BuiltinLib(), NewString("_libraryFilePath"),
-                     kNumArgs, dart_args);
+  return Dart_Invoke(DartUtils::LookupBuiltinLib(),
+                     NewString("_libraryFilePath"), kNumArgs, dart_args);
 }
 
 Dart_Handle DartUtils::ResolveScript(Dart_Handle url) {
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = url;
-  return Dart_Invoke(DartUtils::BuiltinLib(), NewString("_resolveScriptUri"),
-                     kNumArgs, dart_args);
+  return Dart_Invoke(DartUtils::LookupBuiltinLib(),
+                     NewString("_resolveScriptUri"), kNumArgs, dart_args);
 }
 
 static bool CheckMagicNumber(const uint8_t* buffer,
@@ -569,16 +567,16 @@
     const int kNumArgs = 1;
     Dart_Handle dart_args[kNumArgs];
     dart_args[0] = result;
-    result = Dart_Invoke(DartUtils::BuiltinLib(), NewString("_setPackageRoot"),
-                         kNumArgs, dart_args);
+    result = Dart_Invoke(DartUtils::LookupBuiltinLib(),
+                         NewString("_setPackageRoot"), kNumArgs, dart_args);
   } else if (packages_config != NULL) {
     result = NewString(packages_config);
     RETURN_IF_ERROR(result);
     const int kNumArgs = 1;
     Dart_Handle dart_args[kNumArgs];
     dart_args[0] = result;
-    result = Dart_Invoke(DartUtils::BuiltinLib(), NewString("_setPackagesMap"),
-                         kNumArgs, dart_args);
+    result = Dart_Invoke(DartUtils::LookupBuiltinLib(),
+                         NewString("_setPackagesMap"), kNumArgs, dart_args);
   }
   return result;
 }
@@ -613,13 +611,6 @@
   RETURN_IF_ERROR(cli_lib);
   Builtin::SetNativeResolver(Builtin::kCLILibrary);
 
-  // Setup the builtin library in a persistent handle attached the isolate
-  // specific data as we seem to lookup and use builtin lib a lot.
-  IsolateData* isolate_data =
-      reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
-  ASSERT(isolate_data != NULL);
-  isolate_data->set_builtin_lib(builtin_lib);
-
   // We need to ensure that all the scripts loaded so far are finalized
   // as we are about to invoke some Dart code below to setup closures.
   Dart_Handle result = Dart_FinalizeLoading(false);
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 661ec7f..68cd47f 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -204,10 +204,8 @@
   static Dart_Handle NewError(const char* format, ...);
   static Dart_Handle NewInternalError(const char* message);
 
-  static Dart_Handle BuiltinLib() {
-    IsolateData* isolate_data =
-        reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
-    return isolate_data->builtin_lib();
+  static Dart_Handle LookupBuiltinLib() {
+    return Dart_LookupLibrary(NewString(kBuiltinLibURL));
   }
 
   static bool SetOriginalWorkingDirectory();
diff --git a/runtime/bin/isolate_data.cc b/runtime/bin/isolate_data.cc
index c7f1779..dfd440c 100644
--- a/runtime/bin/isolate_data.cc
+++ b/runtime/bin/isolate_data.cc
@@ -15,7 +15,6 @@
     : script_url((url != NULL) ? strdup(url) : NULL),
       package_root(NULL),
       packages_file(NULL),
-      builtin_lib_(NULL),
       loader_(NULL),
       app_snapshot_(app_snapshot),
       dependencies_(NULL),
@@ -32,10 +31,6 @@
 }
 
 void IsolateData::OnIsolateShutdown() {
-  if (builtin_lib_ != NULL) {
-    Dart_DeletePersistentHandle(builtin_lib_);
-    builtin_lib_ = NULL;
-  }
 }
 
 IsolateData::~IsolateData() {
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 575d1b0..ceab601 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -36,18 +36,6 @@
               AppSnapshot* app_snapshot);
   ~IsolateData();
 
-  Dart_Handle builtin_lib() const {
-    ASSERT(builtin_lib_ != NULL);
-    ASSERT(!Dart_IsError(builtin_lib_));
-    return builtin_lib_;
-  }
-  void set_builtin_lib(Dart_Handle lib) {
-    ASSERT(builtin_lib_ == NULL);
-    ASSERT(lib != NULL);
-    ASSERT(!Dart_IsError(lib));
-    builtin_lib_ = Dart_NewPersistentHandle(lib);
-  }
-
   char* script_url;
   char* package_root;
   char* packages_file;
@@ -99,7 +87,6 @@
   void OnIsolateShutdown();
 
  private:
-  Dart_Handle builtin_lib_;
   Loader* loader_;
   AppSnapshot* app_snapshot_;
   MallocGrowableArray<char*>* dependencies_;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 38b59c3..51bbe73 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -7,6 +7,7 @@
 #include <string.h>
 
 #include "include/dart_api.h"
+#include "include/dart_embedder_api.h"
 #include "include/dart_tools_api.h"
 
 #include "bin/builtin.h"
@@ -267,11 +268,6 @@
   Dart_EnterScope();
   Dart_Handle library = Dart_LoadScriptFromKernel(payload, payload_length);
   CHECK_RESULT(library);
-  Dart_Handle url = DartUtils::NewString("dart:_builtin");
-  CHECK_RESULT(url);
-  Dart_Handle builtin_lib = Dart_LookupLibrary(url);
-  CHECK_RESULT(builtin_lib);
-  isolate_data->set_builtin_lib(builtin_lib);
   Dart_ExitScope();
   Dart_ExitIsolate();
 
@@ -1018,7 +1014,7 @@
     Dart_Handle root_lib = Dart_RootLibrary();
     // Import the root library into the builtin library so that we can easily
     // lookup the main entry point exported from the root library.
-    result = Dart_LibraryImportLibrary(isolate_data->builtin_lib(), root_lib,
+    result = Dart_LibraryImportLibrary(DartUtils::LookupBuiltinLib(), root_lib,
                                        Dart_Null());
 #if !defined(DART_PRECOMPILED_RUNTIME)
     if (Options::gen_snapshot_kind() == kAppAOT) {
@@ -1222,8 +1218,6 @@
     }
   }
 
-  Thread::InitOnce();
-
   Loader::InitOnce();
 
   if (!DartUtils::SetOriginalWorkingDirectory()) {
@@ -1284,7 +1278,14 @@
     Process::SetExitHook(SnapshotOnExitHook);
   }
 
-  char* error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
+  char* error = nullptr;
+  if (!dart::embedder::InitOnce(&error)) {
+    Log::PrintErr("Stanalone embedder initialization failed: %s\n", error);
+    free(error);
+    Platform::Exit(kErrorExitCode);
+  }
+
+  error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
   if (error != NULL) {
     Log::PrintErr("Setting VM flags failed: %s\n", error);
     free(error);
@@ -1309,10 +1310,6 @@
   }
 #endif
 
-  // Start event handler.
-  TimerUtils::InitOnce();
-  EventHandler::Start();
-
   // Initialize the Dart VM.
   Dart_InitializeParams init_params;
   memset(&init_params, 0, sizeof(init_params));
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 74f96e6..f512dfb 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -41,7 +41,7 @@
   int length_;
 };
 
-#if defined(DART_PRECOMPILED_RUNTIME)
+#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DART2_ONLY_MODE)
 ResourcesEntry __service_bin_resources_[] = {{NULL, NULL, 0}};
 #else
 extern ResourcesEntry __service_bin_resources_[];
@@ -185,7 +185,8 @@
   // Prepare builtin and its dependent libraries for use to resolve URIs.
   // Set up various closures, e.g: printing, timers etc.
   // Set up 'package root' for URI resolution.
-  result = DartUtils::PrepareForScriptLoading(true, false);
+  result = DartUtils::PrepareForScriptLoading(/*is_service_isolate=*/true,
+                                              trace_loading);
   SHUTDOWN_ON_ERROR(result);
 
   if (running_precompiled) {
@@ -261,12 +262,6 @@
       Dart_SetField(library, DartUtils::NewString("_isFuchsia"), is_fuchsia);
   SHUTDOWN_ON_ERROR(result);
 
-  if (trace_loading) {
-    result = Dart_SetField(library, DartUtils::NewString("_traceLoading"),
-                           Dart_True());
-    SHUTDOWN_ON_ERROR(result);
-  }
-
   if (deterministic) {
     result = Dart_SetField(library, DartUtils::NewString("_deterministic"),
                            Dart_True());
diff --git a/runtime/include/dart_embedder_api.h b/runtime/include/dart_embedder_api.h
new file mode 100644
index 0000000..eda9059
--- /dev/null
+++ b/runtime/include/dart_embedder_api.h
@@ -0,0 +1,80 @@
+// 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.
+
+#ifndef RUNTIME_INCLUDE_DART_EMBEDDER_API_H_
+#define RUNTIME_INCLUDE_DART_EMBEDDER_API_H_
+
+#include "dart_api.h"
+#include "dart_tools_api.h"
+
+namespace dart {
+namespace embedder {
+
+// Initialize all subsystems of the embedder.
+// Returns true on success and false otherwise, in which case error would
+// contain error message.
+DART_WARN_UNUSED_RESULT bool InitOnce(char** error);
+
+// Common arguments that are passed to isolate creation callback and to
+// API methods that create isolates.
+struct IsolateCreationData {
+  // URI for the main script that will be running in the isolate.
+  const char* script_uri;
+
+  // Advisory name of the main method that will be run by isolate.
+  // Only used for error messages.
+  const char* main;
+
+  // Isolate creation flags. Might be absent.
+  Dart_IsolateFlags* flags;
+
+  // Isolate callback data.
+  void* callback_data;
+};
+
+// Create and initialize kernel-service isolate. This method should be used
+// when VM invokes isolate creation callback with DART_KERNEL_ISOLATE_NAME as
+// script_uri.
+// The isolate is created from the given snapshot (might be kernel data or
+// app-jit snapshot).
+DART_WARN_UNUSED_RESULT Dart_Isolate
+CreateKernelServiceIsolate(const IsolateCreationData& data,
+                           const uint8_t* buffer,
+                           intptr_t buffer_size,
+                           char** error);
+
+// Service isolate configuration.
+struct VmServiceConfiguration {
+  enum {
+    kBindHttpServerToAFreePort = 0,
+    kDoNotAutoStartHttpServer = -1
+  };
+
+  // Address to which HTTP server will be bound.
+  const char* ip;
+
+  // Default port. See enum above for special values.
+  int port;
+
+  // TODO(vegorov) document these ones.
+  bool dev_mode;
+  bool deterministic;
+};
+
+// Create and initialize vm-service isolate. This method should be used
+// when VM invokes isolate creation callback with DART_VM_SERVICE_ISOLATE_NAME
+// as script_uri.
+// The isolate is created from the given kernel binary that is expected to
+// contain all necessary vmservice libraries.
+DART_WARN_UNUSED_RESULT Dart_Isolate
+CreateVmServiceIsolate(const IsolateCreationData& data,
+                       const VmServiceConfiguration& config,
+                       const uint8_t* kernel_buffer,
+                       intptr_t kernel_buffer_size,
+                       char** error);
+
+}  // namespace embedder
+}  // namespace dart
+
+#endif  // RUNTIME_INCLUDE_DART_EMBEDDER_API_H_
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index c065f34..89c1883 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -213,7 +213,7 @@
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = DartUtils::NewString(uri_chars);
-  return Dart_Invoke(DartUtils::BuiltinLib(),
+  return Dart_Invoke(DartUtils::LookupBuiltinLib(),
                      DartUtils::NewString("_filePathFromUri"), kNumArgs,
                      dart_args);
 }