Files
sdk/runtime/bin/dfe.cc
T
asiva c6f55f7478 [VM] Use the incremental compiler to compile sources only when the observatory
server is started.

When the incremental compiler is used it accumulates state that
increases the footprint of the process. This state is needed only
when the 'reload' or 'expression evaluation' functionality is used
in the debugger.

Currently in the VM we do not have a good way of detecting when the
debugger will be used as the vm service observatory functionality
can be turned on dynamically after the program has started.

This CL turns on the incremental compiler only when command line options
are used to start the observatory server. We could run into issues with
'expression evaluation' when the observatory is started dynamically after
the program is loaded.

Change-Id: I18c17698622071bca428018f7fdac1a84b0f195e
Reviewed-on: https://dart-review.googlesource.com/64667
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Siva Annamalai <asiva@google.com>
2018-07-13 23:28:51 +00:00

295 lines
9.3 KiB
C++

// Copyright (c) 2017, 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 "bin/dfe.h"
#include "bin/dartutils.h"
#include "bin/directory.h"
#include "bin/error_exit.h"
#include "bin/file.h"
#include "bin/platform.h"
#include "bin/utils.h"
#include "include/dart_tools_api.h"
#include "platform/utils.h"
#include "vm/os.h"
extern "C" {
#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
extern const uint8_t kKernelServiceDill[];
extern intptr_t kKernelServiceDillSize;
extern const uint8_t kPlatformDill[];
extern intptr_t kPlatformDillSize;
extern const uint8_t kPlatformStrongDill[];
extern intptr_t kPlatformStrongDillSize;
#else
const uint8_t* kKernelServiceDill = NULL;
intptr_t kKernelServiceDillSize = 0;
const uint8_t* kPlatformDill = NULL;
intptr_t kPlatformDillSize = 0;
const uint8_t* kPlatformStrongDill = NULL;
intptr_t kPlatformStrongDillSize = 0;
#endif // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
}
namespace dart {
namespace bin {
#if !defined(DART_PRECOMPILED_RUNTIME)
DFE dfe;
#endif
#if defined(DART_NO_SNAPSHOT) || defined(DART_PRECOMPILER)
const uint8_t* kernel_service_dill = NULL;
const intptr_t kernel_service_dill_size = 0;
const uint8_t* platform_dill = NULL;
const intptr_t platform_dill_size = 0;
const uint8_t* platform_strong_dill = NULL;
const intptr_t platform_strong_dill_size = 0;
#else
const uint8_t* kernel_service_dill = kKernelServiceDill;
const intptr_t kernel_service_dill_size = kKernelServiceDillSize;
const uint8_t* platform_dill = kPlatformDill;
const intptr_t platform_dill_size = kPlatformDillSize;
const uint8_t* platform_strong_dill = kPlatformStrongDill;
const intptr_t platform_strong_dill_size = kPlatformStrongDillSize;
#endif
const char kKernelServiceSnapshot[] = "kernel-service.dart.snapshot";
const char kSnapshotsDirectory[] = "snapshots";
static char* GetDirectoryPrefixFromExeName() {
const char* name = Platform::GetExecutableName();
const char* sep = File::PathSeparator();
const intptr_t sep_length = strlen(sep);
for (intptr_t i = strlen(name) - 1; i >= 0; --i) {
const char* str = name + i;
if (strncmp(str, sep, sep_length) == 0
#if defined(HOST_OS_WINDOWS)
// TODO(aam): GetExecutableName doesn't work reliably on Windows,
// the code below is a workaround for that (we would be using
// just single Platform::Separator instead of both slashes if it did).
|| *str == '/'
#endif
) {
return Utils::StrNDup(name, i + 1);
}
}
return strdup("");
}
DFE::DFE()
: use_dfe_(false),
use_incremental_compiler_(false),
frontend_filename_(NULL),
application_kernel_buffer_(NULL),
application_kernel_buffer_size_(0) {}
DFE::~DFE() {
if (frontend_filename_ != NULL) {
free(frontend_filename_);
}
frontend_filename_ = NULL;
free(application_kernel_buffer_);
application_kernel_buffer_ = NULL;
application_kernel_buffer_size_ = 0;
}
void DFE::Init() {
if (platform_dill == NULL) {
return;
}
if (frontend_filename_ == NULL) {
// Look for the frontend snapshot next to the executable.
char* dir_prefix = GetDirectoryPrefixFromExeName();
// |dir_prefix| includes the last path seperator.
frontend_filename_ =
OS::SCreate(NULL, "%s%s", dir_prefix, kKernelServiceSnapshot);
if (!File::Exists(NULL, frontend_filename_)) {
// If the frontend snapshot is not found next to the executable,
// then look for it in the "snapshots" directory.
free(frontend_filename_);
// |dir_prefix| includes the last path seperator.
frontend_filename_ =
OS::SCreate(NULL, "%s%s%s%s", dir_prefix, kSnapshotsDirectory,
File::PathSeparator(), kKernelServiceSnapshot);
}
free(dir_prefix);
if (!File::Exists(NULL, frontend_filename_)) {
free(frontend_filename_);
frontend_filename_ = NULL;
}
}
}
bool DFE::KernelServiceDillAvailable() {
return kernel_service_dill != NULL;
}
void DFE::LoadKernelService(const uint8_t** kernel_service_buffer,
intptr_t* kernel_service_buffer_size) {
*kernel_service_buffer = kernel_service_dill;
*kernel_service_buffer_size = kernel_service_dill_size;
}
void DFE::LoadPlatform(const uint8_t** kernel_buffer,
intptr_t* kernel_buffer_size,
bool strong) {
if (strong) {
*kernel_buffer = platform_strong_dill;
*kernel_buffer_size = platform_strong_dill_size;
} else {
*kernel_buffer = platform_dill;
*kernel_buffer_size = platform_dill_size;
}
}
bool DFE::CanUseDartFrontend() const {
return (platform_dill != NULL) &&
(KernelServiceDillAvailable() || (frontend_filename() != NULL));
}
class WindowsPathSanitizer {
public:
explicit WindowsPathSanitizer(const char* path) {
// For Windows we need to massage the paths a bit according to
// http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx
//
// Convert
// C:\one\two\three
// to
// /C:/one/two/three
//
// (see builtin.dart#_sanitizeWindowsPath)
intptr_t len = strlen(path);
sanitized_uri_ = reinterpret_cast<char*>(malloc(len + 1 + 1));
if (sanitized_uri_ == NULL) {
OUT_OF_MEMORY();
}
char* s = sanitized_uri_;
if (len > 2 && path[1] == ':') {
*s++ = '/';
}
for (const char *p = path; *p; ++p, ++s) {
*s = *p == '\\' ? '/' : *p;
}
*s = '\0';
}
~WindowsPathSanitizer() { free(sanitized_uri_); }
const char* sanitized_uri() { return sanitized_uri_; }
private:
char* sanitized_uri_;
DISALLOW_COPY_AND_ASSIGN(WindowsPathSanitizer);
};
Dart_KernelCompilationResult DFE::CompileScript(const char* script_uri,
bool strong,
bool incremental,
const char* package_config) {
// TODO(aam): When Frontend is ready, VM should be passing vm_outline.dill
// instead of vm_platform.dill to Frontend for compilation.
#if defined(HOST_OS_WINDOWS)
WindowsPathSanitizer path_sanitizer(script_uri);
const char* sanitized_uri = path_sanitizer.sanitized_uri();
#else
const char* sanitized_uri = script_uri;
#endif
const uint8_t* platform_binary =
strong ? platform_strong_dill : platform_dill;
intptr_t platform_binary_size =
strong ? platform_strong_dill_size : platform_dill_size;
return Dart_CompileToKernel(sanitized_uri, platform_binary,
platform_binary_size, incremental,
package_config);
}
void DFE::CompileAndReadScript(const char* script_uri,
uint8_t** kernel_buffer,
intptr_t* kernel_buffer_size,
char** error,
int* exit_code,
bool strong,
const char* package_config) {
Dart_KernelCompilationResult result = CompileScript(
script_uri, strong, use_incremental_compiler(), package_config);
switch (result.status) {
case Dart_KernelCompilationStatus_Ok:
*kernel_buffer = result.kernel;
*kernel_buffer_size = result.kernel_size;
*error = NULL;
*exit_code = 0;
break;
case Dart_KernelCompilationStatus_Error:
*error = result.error; // Copy error message.
*exit_code = kCompilationErrorExitCode;
break;
case Dart_KernelCompilationStatus_Crash:
*error = result.error; // Copy error message.
*exit_code = kDartFrontendErrorExitCode;
break;
case Dart_KernelCompilationStatus_Unknown:
*error = result.error; // Copy error message.
*exit_code = kErrorExitCode;
break;
}
}
void DFE::ReadScript(const char* script_uri,
uint8_t** kernel_buffer,
intptr_t* kernel_buffer_size) const {
int64_t start = Dart_TimelineGetMicros();
if (!TryReadKernelFile(script_uri, kernel_buffer, kernel_buffer_size)) {
return;
}
if (!Dart_IsKernel(*kernel_buffer, *kernel_buffer_size)) {
free(*kernel_buffer);
*kernel_buffer = NULL;
*kernel_buffer_size = -1;
}
int64_t end = Dart_TimelineGetMicros();
Dart_TimelineEvent("DFE::ReadScript", start, end,
Dart_Timeline_Event_Duration, 0, NULL, NULL);
}
bool DFE::TryReadKernelFile(const char* script_uri,
uint8_t** kernel_ir,
intptr_t* kernel_ir_size) {
*kernel_ir = NULL;
*kernel_ir_size = -1;
void* script_file = DartUtils::OpenFileUri(script_uri, false);
if (script_file == NULL) {
return false;
}
uint8_t* buffer = NULL;
DartUtils::ReadFile(&buffer, kernel_ir_size, script_file);
DartUtils::CloseFile(script_file);
if (*kernel_ir_size == 0 || buffer == NULL) {
return false;
}
if (DartUtils::SniffForMagicNumber(buffer, *kernel_ir_size) !=
DartUtils::kKernelMagicNumber) {
free(buffer);
*kernel_ir = NULL;
*kernel_ir_size = -1;
return false;
}
// Do not free buffer if this is a kernel file - kernel_file will be
// backed by the same memory as the buffer and caller will own it.
// Caller is responsible for freeing the buffer when this function
// returns true.
*kernel_ir = buffer;
return true;
}
} // namespace bin
} // namespace dart