blob: b7616aab82018de12dfa16e99ed3d27d085627a6 [file] [log] [blame]
// Copyright (c) 2012, 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/console.h"
#include "bin/dartutils.h"
#include "bin/dfe.h"
#include "bin/eventhandler.h"
#include "bin/file.h"
#include "bin/loader.h"
#include "bin/platform.h"
#include "bin/snapshot_utils.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "platform/assert.h"
#include "vm/benchmark_test.h"
#include "vm/dart.h"
#include "vm/unit_test.h"
extern "C" {
extern const uint8_t kDartVmSnapshotData[];
extern const uint8_t kDartVmSnapshotInstructions[];
extern const uint8_t kDartCoreIsolateSnapshotData[];
extern const uint8_t kDartCoreIsolateSnapshotInstructions[];
}
// TODO(iposva, asiva): This is a placeholder for the real unittest framework.
namespace dart {
// Defined in vm/os_thread_win.cc
extern bool private_flag_windows_run_tls_destructors;
// Snapshot pieces when we link in a snapshot.
#if defined(DART_NO_SNAPSHOT)
#error "run_vm_tests must be built with a snapshot"
#else
const uint8_t* bin::vm_snapshot_data = kDartVmSnapshotData;
const uint8_t* bin::vm_snapshot_instructions = kDartVmSnapshotInstructions;
const uint8_t* bin::core_isolate_snapshot_data = kDartCoreIsolateSnapshotData;
const uint8_t* bin::core_isolate_snapshot_instructions =
kDartCoreIsolateSnapshotInstructions;
#endif
// Only run tests that match the filter string. The default does not match any
// tests.
static const char* const kNone = "No Test or Benchmarks";
static const char* const kList = "List all Tests and Benchmarks";
static const char* const kAllBenchmarks = "All Benchmarks";
static const char* run_filter = kNone;
static const char* kernel_snapshot = NULL;
static int run_matches = 0;
void TestCase::Run() {
bin::Log::Print("Running test: %s\n", name());
(*run_)();
bin::Log::Print("Done: %s\n", name());
}
void RawTestCase::Run() {
bin::Log::Print("Running raw test: %s\n", name());
(*run_)();
bin::Log::Print("Done: %s\n", name());
}
void TestCaseBase::RunTest() {
if (strcmp(run_filter, this->name()) == 0) {
this->Run();
run_matches++;
} else if (run_filter == kList) {
bin::Log::Print("%s\n", this->name());
run_matches++;
}
}
void Benchmark::RunBenchmark() {
if ((run_filter == kAllBenchmarks) ||
(strcmp(run_filter, this->name()) == 0)) {
this->Run();
bin::Log::Print("%s(%s): %" Pd64 "\n", this->name(), this->score_kind(),
this->score());
run_matches++;
} else if (run_filter == kList) {
bin::Log::Print("%s\n", this->name());
run_matches++;
}
}
static void PrintUsage() {
bin::Log::PrintErr(
"Usage: one of the following\n"
" run_vm_tests --list\n"
" run_vm_tests [--dfe=<snapshot file name>] --benchmarks\n"
" run_vm_tests [--dfe=<snapshot file name>] [vm-flags ...] <test name>\n"
" run_vm_tests [--dfe=<snapshot file name>] [vm-flags ...] <benchmark "
"name>\n");
}
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
*error = strdup(Dart_GetError(result)); \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
return NULL; \
}
static Dart_Isolate CreateIsolateAndSetup(const char* script_uri,
const char* main,
const char* package_root,
const char* packages_config,
Dart_IsolateFlags* flags,
void* data,
char** error) {
ASSERT(script_uri != NULL);
const bool is_service_isolate =
strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0;
if (is_service_isolate) {
// We don't need service isolate for VM tests.
return NULL;
}
const bool is_kernel_isolate =
strcmp(script_uri, DART_KERNEL_ISOLATE_NAME) == 0;
if (!is_kernel_isolate) {
*error =
strdup("Spawning of only Kernel isolate is supported in run_vm_tests.");
return NULL;
}
Dart_Isolate isolate = NULL;
bin::IsolateData* isolate_data = NULL;
const uint8_t* kernel_service_buffer = NULL;
intptr_t kernel_service_buffer_size = 0;
// Kernel isolate uses an app snapshot or the kernel service dill file.
if (kernel_snapshot != NULL &&
(bin::DartUtils::SniffForMagicNumber(kernel_snapshot) ==
bin::DartUtils::kAppJITMagicNumber)) {
script_uri = kernel_snapshot;
bin::AppSnapshot* app_snapshot =
bin::Snapshot::TryReadAppSnapshot(script_uri);
ASSERT(app_snapshot != NULL);
const uint8_t* ignore_vm_snapshot_data;
const uint8_t* ignore_vm_snapshot_instructions;
const uint8_t* isolate_snapshot_data;
const uint8_t* isolate_snapshot_instructions;
app_snapshot->SetBuffers(
&ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions,
&isolate_snapshot_data, &isolate_snapshot_instructions);
isolate_data = new bin::IsolateData(script_uri, package_root,
packages_config, app_snapshot);
isolate = Dart_CreateIsolate(
DART_KERNEL_ISOLATE_NAME, main, isolate_snapshot_data,
isolate_snapshot_instructions, NULL, NULL, flags, isolate_data, error);
}
if (isolate == NULL) {
bin::dfe.Init();
bin::dfe.LoadKernelService(&kernel_service_buffer,
&kernel_service_buffer_size);
ASSERT(kernel_service_buffer != NULL);
isolate_data =
new bin::IsolateData(script_uri, package_root, packages_config, NULL);
isolate_data->set_kernel_buffer(const_cast<uint8_t*>(kernel_service_buffer),
kernel_service_buffer_size,
false /* take_ownership */);
isolate = Dart_CreateIsolateFromKernel(
script_uri, main, kernel_service_buffer, kernel_service_buffer_size,
flags, isolate_data, error);
}
if (isolate == NULL) {
delete isolate_data;
return NULL;
}
Dart_EnterScope();
bin::DartUtils::SetOriginalWorkingDirectory();
Dart_Handle result = bin::DartUtils::PrepareForScriptLoading(
false /* is_service_isolate */, false /* trace_loading */);
CHECK_RESULT(result);
// Setup kernel service as the main script for this isolate.
if (kernel_service_buffer) {
result = Dart_LoadScriptFromKernel(kernel_service_buffer,
kernel_service_buffer_size);
CHECK_RESULT(result);
}
Dart_ExitScope();
Dart_ExitIsolate();
*error = Dart_IsolateMakeRunnable(isolate);
if (*error != NULL) {
Dart_EnterIsolate(isolate);
Dart_ShutdownIsolate();
return NULL;
}
return isolate;
}
static void CleanupIsolate(void* callback_data) {
bin::IsolateData* isolate_data =
reinterpret_cast<bin::IsolateData*>(callback_data);
delete isolate_data;
}
static int Main(int argc, const char** argv) {
// Flags being passed to the Dart VM.
int dart_argc = 0;
const char** dart_argv = NULL;
// Perform platform specific initialization.
if (!dart::bin::Platform::Initialize()) {
bin::Log::PrintErr("Initialization failed\n");
return 1;
}
// Save the console state so we can restore it later.
dart::bin::Console::SaveConfig();
// Store the executable name.
dart::bin::Platform::SetExecutableName(argv[0]);
if (argc < 2) {
// Bad parameter count.
PrintUsage();
return 1;
}
if (argc == 2 && strcmp(argv[1], "--list") == 0) {
run_filter = kList;
// List all tests and benchmarks and exit without initializing the VM.
TestCaseBase::RunAll();
Benchmark::RunAll(argv[0]);
TestCaseBase::RunAllRaw();
fflush(stdout);
return 0;
}
int arg_pos = 1;
bool start_kernel_isolate = false;
if (strstr(argv[arg_pos], "--dfe") == argv[arg_pos]) {
const char* delim = strstr(argv[1], "=");
if (delim == NULL || strlen(delim + 1) == 0) {
bin::Log::PrintErr("Invalid value for the option: %s\n", argv[1]);
PrintUsage();
return 1;
}
kernel_snapshot = strdup(delim + 1);
// VM needs '--use-dart-frontend' option, which we will insert in place
// of '--dfe' option.
argv[arg_pos] = strdup("--use-dart-frontend");
start_kernel_isolate = true;
++arg_pos;
}
if (arg_pos == argc - 1 && strcmp(argv[arg_pos], "--benchmarks") == 0) {
// "--benchmarks" is the last argument.
run_filter = kAllBenchmarks;
} else {
// Last argument is the test name, the rest are vm flags.
run_filter = argv[argc - 1];
// Remove the first value (executable) from the arguments and
// exclude the last argument which is the test name.
dart_argc = argc - 2;
dart_argv = &argv[1];
}
bin::Thread::InitOnce();
bin::TimerUtils::InitOnce();
bin::EventHandler::Start();
const char* error;
if (!start_kernel_isolate) {
int extra_argc = dart_argc + 3;
const char** extra_argv = new const char*[extra_argc];
for (intptr_t i = 0; i < dart_argc; i++) {
extra_argv[i] = dart_argv[i];
}
extra_argv[dart_argc] = "--no-strong";
extra_argv[dart_argc + 1] = "--no-reify_generic_functions";
extra_argv[dart_argc + 2] = "--no-sync-async";
error = Flags::ProcessCommandLineFlags(extra_argc, extra_argv);
delete[] extra_argv;
ASSERT(error == NULL);
} else {
error = Flags::ProcessCommandLineFlags(dart_argc, dart_argv);
ASSERT(error == NULL);
}
error = Dart::InitOnce(
dart::bin::vm_snapshot_data, dart::bin::vm_snapshot_instructions,
CreateIsolateAndSetup /* create */, NULL /* shutdown */,
CleanupIsolate /* cleanup */, NULL /* thread_exit */,
dart::bin::DartUtils::OpenFile, dart::bin::DartUtils::ReadFile,
dart::bin::DartUtils::WriteFile, dart::bin::DartUtils::CloseFile,
NULL /* entropy_source */, NULL /* get_service_assets */,
start_kernel_isolate);
ASSERT(error == NULL);
// Apply the filter to all registered tests.
TestCaseBase::RunAll();
// Apply the filter to all registered benchmarks.
Benchmark::RunAll(argv[0]);
error = Dart::Cleanup();
ASSERT(error == NULL);
bin::EventHandler::Stop();
TestCaseBase::RunAllRaw();
// Print a warning message if no tests or benchmarks were matched.
if (run_matches == 0) {
bin::Log::PrintErr("No tests matched: %s\n", run_filter);
return 1;
}
if (Expect::failed()) {
return 255;
}
return 0;
}
} // namespace dart
int main(int argc, const char** argv) {
dart::bin::Platform::Exit(dart::Main(argc, argv));
}