mirror of
https://github.com/encounter/engine.git
synced 2026-03-30 11:09:55 -07:00
73554a1c32
This repository contains FTL now in the Fuchsia build.
219 lines
7.5 KiB
C++
219 lines
7.5 KiB
C++
// Copyright 2015 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "flutter/runtime/dart_controller.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "dart/runtime/include/dart_tools_api.h"
|
|
#include "flutter/common/settings.h"
|
|
#include "flutter/common/threads.h"
|
|
#include "flutter/glue/trace_event.h"
|
|
#include "flutter/lib/io/dart_io.h"
|
|
#include "flutter/lib/ui/dart_runtime_hooks.h"
|
|
#include "flutter/lib/ui/dart_ui.h"
|
|
#include "flutter/lib/ui/ui_dart_state.h"
|
|
#include "flutter/runtime/dart_init.h"
|
|
#include "flutter/runtime/dart_service_isolate.h"
|
|
#include "lib/ftl/files/directory.h"
|
|
#include "lib/ftl/files/path.h"
|
|
#include "lib/tonic/dart_class_library.h"
|
|
#include "lib/tonic/dart_message_handler.h"
|
|
#include "lib/tonic/dart_state.h"
|
|
#include "lib/tonic/dart_wrappable.h"
|
|
#include "lib/tonic/debugger/dart_debugger.h"
|
|
#include "lib/tonic/file_loader/file_loader.h"
|
|
#include "lib/tonic/logging/dart_error.h"
|
|
#include "lib/tonic/logging/dart_invoke.h"
|
|
#include "lib/tonic/scopes/dart_api_scope.h"
|
|
#include "lib/tonic/scopes/dart_isolate_scope.h"
|
|
|
|
using tonic::LogIfError;
|
|
using tonic::ToDart;
|
|
|
|
namespace blink {
|
|
namespace {
|
|
|
|
// TODO(abarth): Consider adding this to //garnet/public/lib/ftl.
|
|
std::string ResolvePath(std::string path) {
|
|
if (!path.empty() && path[0] == '/')
|
|
return path;
|
|
return files::SimplifyPath(files::GetCurrentDirectory() + "/" + path);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
DartController::DartController() : ui_dart_state_(nullptr),
|
|
kernel_bytes(nullptr), platform_kernel_bytes(nullptr) {}
|
|
|
|
DartController::~DartController() {
|
|
if (ui_dart_state_) {
|
|
// Don't use a tonic::DartIsolateScope here since we never exit the isolate.
|
|
Dart_EnterIsolate(ui_dart_state_->isolate());
|
|
// Clear the message notify callback.
|
|
Dart_SetMessageNotifyCallback(nullptr);
|
|
Dart_ShutdownIsolate(); // deletes ui_dart_state_
|
|
ui_dart_state_ = nullptr;
|
|
}
|
|
if (kernel_bytes) {
|
|
free(kernel_bytes);
|
|
}
|
|
if (platform_kernel_bytes) {
|
|
free(platform_kernel_bytes);
|
|
}
|
|
}
|
|
|
|
bool DartController::SendStartMessage(Dart_Handle root_library) {
|
|
if (LogIfError(root_library))
|
|
return true;
|
|
|
|
{
|
|
// Temporarily exit the isolate while we make it runnable.
|
|
Dart_Isolate isolate = dart_state()->isolate();
|
|
FTL_DCHECK(Dart_CurrentIsolate() == isolate);
|
|
Dart_ExitIsolate();
|
|
Dart_IsolateMakeRunnable(isolate);
|
|
Dart_EnterIsolate(isolate);
|
|
}
|
|
|
|
// In order to support pausing the isolate at start, we indirectly invoke
|
|
// main by sending a message to the isolate.
|
|
|
|
// Get the closure of main().
|
|
Dart_Handle main_closure =
|
|
Dart_GetClosure(root_library, Dart_NewStringFromCString("main"));
|
|
if (LogIfError(main_closure))
|
|
return true;
|
|
|
|
// Grab the 'dart:isolate' library.
|
|
Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
|
|
DART_CHECK_VALID(isolate_lib);
|
|
|
|
// Send the start message containing the entry point by calling
|
|
// _startMainIsolate in dart:isolate.
|
|
const intptr_t kNumIsolateArgs = 2;
|
|
Dart_Handle isolate_args[kNumIsolateArgs];
|
|
isolate_args[0] = main_closure;
|
|
isolate_args[1] = Dart_Null();
|
|
Dart_Handle result = Dart_Invoke(isolate_lib, ToDart("_startMainIsolate"),
|
|
kNumIsolateArgs, isolate_args);
|
|
return LogIfError(result);
|
|
}
|
|
|
|
static void CopyVectorBytes(const std::vector<uint8_t>& vector,
|
|
uint8_t*& bytes) {
|
|
if (bytes) {
|
|
free(bytes);
|
|
}
|
|
bytes = (uint8_t*) malloc(vector.size());
|
|
memcpy(bytes, vector.data(), vector.size());
|
|
}
|
|
|
|
tonic::DartErrorHandleType DartController::RunFromKernel(
|
|
const std::vector<uint8_t>& kernel) {
|
|
tonic::DartState::Scope scope(dart_state());
|
|
// Copy kernel bytes so they won't go away after we exit this method.
|
|
// This is needed because original kernel data has to be available
|
|
// during code execution.
|
|
CopyVectorBytes(kernel, kernel_bytes);
|
|
|
|
Dart_Handle result = Dart_LoadKernel(
|
|
Dart_ReadKernelBinary(kernel_bytes, kernel.size()));
|
|
LogIfError(result);
|
|
tonic::DartErrorHandleType error = tonic::GetErrorHandleType(result);
|
|
if (SendStartMessage(Dart_RootLibrary())) {
|
|
return tonic::kUnknownErrorType;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
tonic::DartErrorHandleType DartController::RunFromPrecompiledSnapshot() {
|
|
TRACE_EVENT0("flutter", "DartController::RunFromPrecompiledSnapshot");
|
|
FTL_DCHECK(Dart_CurrentIsolate() == nullptr);
|
|
tonic::DartState::Scope scope(dart_state());
|
|
if (SendStartMessage(Dart_RootLibrary())) {
|
|
return tonic::kUnknownErrorType;
|
|
}
|
|
return tonic::kNoError;
|
|
}
|
|
|
|
tonic::DartErrorHandleType DartController::RunFromScriptSnapshot(
|
|
const uint8_t* buffer, size_t size) {
|
|
tonic::DartState::Scope scope(dart_state());
|
|
Dart_Handle result = Dart_LoadScriptFromSnapshot(buffer, size);
|
|
LogIfError(result);
|
|
tonic::DartErrorHandleType error = tonic::GetErrorHandleType(result);
|
|
if (SendStartMessage(Dart_RootLibrary())) {
|
|
return tonic::kUnknownErrorType;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
tonic::DartErrorHandleType DartController::RunFromSource(
|
|
const std::string& main, const std::string& packages) {
|
|
tonic::DartState::Scope scope(dart_state());
|
|
tonic::FileLoader& loader = dart_state()->file_loader();
|
|
if (!packages.empty() && !loader.LoadPackagesMap(ResolvePath(packages)))
|
|
FTL_LOG(WARNING) << "Failed to load package map: " << packages;
|
|
Dart_Handle result = loader.LoadScript(main);
|
|
LogIfError(result);
|
|
tonic::DartErrorHandleType error = tonic::GetErrorHandleType(result);
|
|
if (SendStartMessage(Dart_RootLibrary())) {
|
|
return tonic::kCompilationErrorType;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
void DartController::CreateIsolateFor(const std::string& script_uri,
|
|
const uint8_t* isolate_snapshot_data,
|
|
const uint8_t* isolate_snapshot_instr,
|
|
const std::vector<uint8_t>& platform_kernel,
|
|
std::unique_ptr<UIDartState> state) {
|
|
char* error = nullptr;
|
|
|
|
Dart_Isolate isolate;
|
|
if (!platform_kernel.empty()) {
|
|
// Copy kernel bytes so they won't go away after we exit this method.
|
|
// This is needed because original kernel data has to be available
|
|
// during code execution.
|
|
CopyVectorBytes(platform_kernel, platform_kernel_bytes);
|
|
|
|
isolate = Dart_CreateIsolateFromKernel(
|
|
script_uri.c_str(), "main",
|
|
Dart_ReadKernelBinary(platform_kernel_bytes, platform_kernel.size()),
|
|
nullptr /* flags */,
|
|
static_cast<tonic::DartState*>(state.get()), &error);
|
|
} else {
|
|
isolate = Dart_CreateIsolate(
|
|
script_uri.c_str(), "main", isolate_snapshot_data,
|
|
isolate_snapshot_instr, nullptr,
|
|
static_cast<tonic::DartState*>(state.get()), &error);
|
|
}
|
|
FTL_CHECK(isolate) << error;
|
|
ui_dart_state_ = state.release();
|
|
dart_state()->message_handler().Initialize(blink::Threads::UI());
|
|
|
|
Dart_SetShouldPauseOnStart(Settings::Get().start_paused);
|
|
|
|
ui_dart_state_->set_debug_name_prefix(script_uri);
|
|
ui_dart_state_->SetIsolate(isolate);
|
|
FTL_CHECK(!LogIfError(
|
|
Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag)));
|
|
|
|
{
|
|
tonic::DartApiScope dart_api_scope;
|
|
DartIO::InitForIsolate();
|
|
DartUI::InitForIsolate();
|
|
DartRuntimeHooks::Install(DartRuntimeHooks::MainIsolate, script_uri);
|
|
|
|
std::unique_ptr<tonic::DartClassProvider> ui_class_provider(
|
|
new tonic::DartClassProvider(dart_state(), "dart:ui"));
|
|
dart_state()->class_library().add_provider("ui",
|
|
std::move(ui_class_provider));
|
|
}
|
|
Dart_ExitIsolate();
|
|
}
|
|
|
|
} // namespace blink
|