Remove more things
(stripped) dart_product before: 5307888 (stripped) dart_product after: 5275088 Reduction in size: 32800 bytes. Removed entirely: - debuginfo* - elfgen* - gdbjit* - TraceBuffer - vtune support Removed in product: - Compiler stats - Code observers R=asiva@google.com Review URL: https://codereview.chromium.org/1711163002 .
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
#include "vm/bootstrap_natives.h"
|
||||
|
||||
#include "vm/object.h"
|
||||
#include "vm/report.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "vm/heap.h"
|
||||
#include "vm/native_entry.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/report.h"
|
||||
#include "vm/stack_frame.h"
|
||||
#include "vm/symbols.h"
|
||||
|
||||
|
||||
+111
-102
@@ -26,6 +26,73 @@ Benchmark* Benchmark::first_ = NULL;
|
||||
Benchmark* Benchmark::tail_ = NULL;
|
||||
const char* Benchmark::executable_ = NULL;
|
||||
|
||||
|
||||
//
|
||||
// Measure compile of all dart2js(compiler) functions.
|
||||
//
|
||||
static char* ComputeDart2JSPath(const char* arg) {
|
||||
char buffer[2048];
|
||||
char* dart2js_path = strdup(File::GetCanonicalPath(arg));
|
||||
const char* compiler_path =
|
||||
"%s%spkg%scompiler%slib%scompiler.dart";
|
||||
const char* path_separator = File::PathSeparator();
|
||||
ASSERT(path_separator != NULL && strlen(path_separator) == 1);
|
||||
char* ptr = strrchr(dart2js_path, *path_separator);
|
||||
while (ptr != NULL) {
|
||||
*ptr = '\0';
|
||||
OS::SNPrint(buffer, 2048, compiler_path,
|
||||
dart2js_path,
|
||||
path_separator,
|
||||
path_separator,
|
||||
path_separator,
|
||||
path_separator,
|
||||
path_separator);
|
||||
if (File::Exists(buffer)) {
|
||||
break;
|
||||
}
|
||||
ptr = strrchr(dart2js_path, *path_separator);
|
||||
}
|
||||
if (ptr == NULL) {
|
||||
free(dart2js_path);
|
||||
dart2js_path = NULL;
|
||||
}
|
||||
return dart2js_path;
|
||||
}
|
||||
|
||||
|
||||
static void func(Dart_NativeArguments args) {
|
||||
}
|
||||
|
||||
|
||||
static Dart_NativeFunction NativeResolver(Dart_Handle name,
|
||||
int arg_count,
|
||||
bool* auto_setup_scope) {
|
||||
ASSERT(auto_setup_scope != NULL);
|
||||
*auto_setup_scope = false;
|
||||
return &func;
|
||||
}
|
||||
|
||||
|
||||
static void SetupDart2JSPackagePath() {
|
||||
bool worked = bin::DartUtils::SetOriginalWorkingDirectory();
|
||||
EXPECT(worked);
|
||||
|
||||
Dart_Handle result = bin::DartUtils::PrepareForScriptLoading(false, false);
|
||||
DART_CHECK_VALID(result);
|
||||
|
||||
// Setup package root.
|
||||
char buffer[2048];
|
||||
char* executable_path =
|
||||
strdup(File::GetCanonicalPath(Benchmark::Executable()));
|
||||
const char* packages_path = "%s%s..%spackages";
|
||||
const char* path_separator = File::PathSeparator();
|
||||
OS::SNPrint(buffer, 2048, packages_path,
|
||||
executable_path, path_separator, path_separator);
|
||||
result = bin::DartUtils::SetupPackageRoot(buffer, NULL);
|
||||
DART_CHECK_VALID(result);
|
||||
}
|
||||
|
||||
|
||||
void Benchmark::RunAll(const char* executable) {
|
||||
SetExecutable(executable);
|
||||
Benchmark* benchmark = first_;
|
||||
@@ -66,6 +133,9 @@ BENCHMARK(CorelibCompileAll) {
|
||||
}
|
||||
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
|
||||
BENCHMARK(CorelibCompilerStats) {
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
|
||||
@@ -86,6 +156,47 @@ BENCHMARK(CorelibCompilerStats) {
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(Dart2JSCompilerStats) {
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
|
||||
SetupDart2JSPackagePath();
|
||||
char* dart_root = ComputeDart2JSPath(Benchmark::Executable());
|
||||
char* script = NULL;
|
||||
if (dart_root != NULL) {
|
||||
HANDLESCOPE(thread);
|
||||
script = OS::SCreate(NULL,
|
||||
"import '%s/pkg/compiler/lib/compiler.dart';", dart_root);
|
||||
Dart_Handle lib = TestCase::LoadTestScript(
|
||||
script,
|
||||
reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
|
||||
EXPECT_VALID(lib);
|
||||
} else {
|
||||
Dart_Handle lib = TestCase::LoadTestScript(
|
||||
"import 'pkg/compiler/lib/compiler.dart';",
|
||||
reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
|
||||
EXPECT_VALID(lib);
|
||||
}
|
||||
CompilerStats* stats = thread->isolate()->compiler_stats();
|
||||
ASSERT(stats != NULL);
|
||||
stats->EnableBenchmark();
|
||||
Timer timer(true, "Compile all of dart2js benchmark");
|
||||
timer.Start();
|
||||
const bool old_flag = FLAG_background_compilation;
|
||||
FLAG_background_compilation = false;
|
||||
Dart_Handle result = Dart_CompileAll();
|
||||
FLAG_background_compilation = old_flag;
|
||||
EXPECT_VALID(result);
|
||||
timer.Stop();
|
||||
int64_t elapsed_time = timer.TotalElapsedTime();
|
||||
benchmark->set_score(elapsed_time);
|
||||
free(dart_root);
|
||||
free(script);
|
||||
}
|
||||
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
|
||||
//
|
||||
// Measure creation of core isolate from a snapshot.
|
||||
//
|
||||
@@ -254,70 +365,6 @@ BENCHMARK(DartStringAccess) {
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Measure compile of all dart2js(compiler) functions.
|
||||
//
|
||||
static char* ComputeDart2JSPath(const char* arg) {
|
||||
char buffer[2048];
|
||||
char* dart2js_path = strdup(File::GetCanonicalPath(arg));
|
||||
const char* compiler_path =
|
||||
"%s%spkg%scompiler%slib%scompiler.dart";
|
||||
const char* path_separator = File::PathSeparator();
|
||||
ASSERT(path_separator != NULL && strlen(path_separator) == 1);
|
||||
char* ptr = strrchr(dart2js_path, *path_separator);
|
||||
while (ptr != NULL) {
|
||||
*ptr = '\0';
|
||||
OS::SNPrint(buffer, 2048, compiler_path,
|
||||
dart2js_path,
|
||||
path_separator,
|
||||
path_separator,
|
||||
path_separator,
|
||||
path_separator,
|
||||
path_separator);
|
||||
if (File::Exists(buffer)) {
|
||||
break;
|
||||
}
|
||||
ptr = strrchr(dart2js_path, *path_separator);
|
||||
}
|
||||
if (ptr == NULL) {
|
||||
free(dart2js_path);
|
||||
dart2js_path = NULL;
|
||||
}
|
||||
return dart2js_path;
|
||||
}
|
||||
|
||||
|
||||
static void func(Dart_NativeArguments args) {
|
||||
}
|
||||
|
||||
|
||||
static Dart_NativeFunction NativeResolver(Dart_Handle name,
|
||||
int arg_count,
|
||||
bool* auto_setup_scope) {
|
||||
ASSERT(auto_setup_scope != NULL);
|
||||
*auto_setup_scope = false;
|
||||
return &func;
|
||||
}
|
||||
|
||||
static void SetupDart2JSPackagePath() {
|
||||
bool worked = bin::DartUtils::SetOriginalWorkingDirectory();
|
||||
EXPECT(worked);
|
||||
|
||||
Dart_Handle result = bin::DartUtils::PrepareForScriptLoading(false, false);
|
||||
DART_CHECK_VALID(result);
|
||||
|
||||
// Setup package root.
|
||||
char buffer[2048];
|
||||
char* executable_path =
|
||||
strdup(File::GetCanonicalPath(Benchmark::Executable()));
|
||||
const char* packages_path = "%s%s..%spackages";
|
||||
const char* path_separator = File::PathSeparator();
|
||||
OS::SNPrint(buffer, 2048, packages_path,
|
||||
executable_path, path_separator, path_separator);
|
||||
result = bin::DartUtils::SetupPackageRoot(buffer, NULL);
|
||||
DART_CHECK_VALID(result);
|
||||
}
|
||||
|
||||
BENCHMARK(Dart2JSCompileAll) {
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
|
||||
@@ -353,44 +400,6 @@ BENCHMARK(Dart2JSCompileAll) {
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(Dart2JSCompilerStats) {
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
|
||||
bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
|
||||
SetupDart2JSPackagePath();
|
||||
char* dart_root = ComputeDart2JSPath(Benchmark::Executable());
|
||||
char* script = NULL;
|
||||
if (dart_root != NULL) {
|
||||
HANDLESCOPE(thread);
|
||||
script = OS::SCreate(NULL,
|
||||
"import '%s/pkg/compiler/lib/compiler.dart';", dart_root);
|
||||
Dart_Handle lib = TestCase::LoadTestScript(
|
||||
script,
|
||||
reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
|
||||
EXPECT_VALID(lib);
|
||||
} else {
|
||||
Dart_Handle lib = TestCase::LoadTestScript(
|
||||
"import 'pkg/compiler/lib/compiler.dart';",
|
||||
reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
|
||||
EXPECT_VALID(lib);
|
||||
}
|
||||
CompilerStats* stats = thread->isolate()->compiler_stats();
|
||||
ASSERT(stats != NULL);
|
||||
stats->EnableBenchmark();
|
||||
Timer timer(true, "Compile all of dart2js benchmark");
|
||||
timer.Start();
|
||||
const bool old_flag = FLAG_background_compilation;
|
||||
FLAG_background_compilation = false;
|
||||
Dart_Handle result = Dart_CompileAll();
|
||||
FLAG_background_compilation = old_flag;
|
||||
EXPECT_VALID(result);
|
||||
timer.Stop();
|
||||
int64_t elapsed_time = timer.TotalElapsedTime();
|
||||
benchmark->set_score(elapsed_time);
|
||||
free(dart_root);
|
||||
free(script);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Measure frame lookup during stack traversal.
|
||||
//
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "vm/longjump.h"
|
||||
#include "vm/log.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/report.h"
|
||||
#include "vm/symbols.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "vm/message.h"
|
||||
#include "vm/message_handler.h"
|
||||
#include "vm/parser.h"
|
||||
#include "vm/report.h"
|
||||
#include "vm/resolver.h"
|
||||
#include "vm/runtime_entry.h"
|
||||
#include "vm/stack_frame.h"
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
Mutex* CodeObservers::mutex_ = NULL;
|
||||
intptr_t CodeObservers::observers_length_ = 0;
|
||||
CodeObserver** CodeObservers::observers_ = NULL;
|
||||
@@ -66,4 +68,6 @@ void CodeObservers::InitOnce() {
|
||||
}
|
||||
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
class Mutex;
|
||||
|
||||
// Object observing code creation events. Used by external profilers and
|
||||
@@ -65,6 +67,7 @@ class CodeObservers : public AllStatic {
|
||||
static CodeObserver** observers_;
|
||||
};
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ CompilerStats::CompilerStats(Isolate* isolate)
|
||||
}
|
||||
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
// This function is used as a callback in the log object to which the
|
||||
// compiler stats are printed. It will be called only once, to print
|
||||
// the accumulated text when all of the compiler stats values are
|
||||
@@ -286,4 +288,6 @@ char* CompilerStats::PrintToZone() {
|
||||
return stats_text;
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -72,20 +72,22 @@ class CompilerStats {
|
||||
};
|
||||
|
||||
#define INC_STAT(thread, counter, incr) \
|
||||
if (FLAG_compiler_stats) { \
|
||||
if (FLAG_support_compiler_stats && FLAG_compiler_stats) { \
|
||||
MutexLocker ml((thread)->isolate()->mutex()); \
|
||||
(thread)->isolate()->compiler_stats()->counter += (incr); \
|
||||
}
|
||||
|
||||
#define STAT_VALUE(thread, counter) \
|
||||
((FLAG_compiler_stats != false) ? \
|
||||
((FLAG_support_compiler_stats && FLAG_compiler_stats) ? \
|
||||
(thread)->isolate()->compiler_stats()->counter : 0)
|
||||
|
||||
#define CSTAT_TIMER_SCOPE(thr, t) \
|
||||
TimerScope timer(FLAG_compiler_stats, \
|
||||
FLAG_compiler_stats ? &((thr)->isolate()->compiler_stats()->t) : NULL, \
|
||||
TimerScope timer(FLAG_support_compiler_stats && FLAG_compiler_stats, \
|
||||
(FLAG_support_compiler_stats && FLAG_compiler_stats) ? \
|
||||
&((thr)->isolate()->compiler_stats()->t) : NULL, \
|
||||
thr);
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_COMPILER_STATS_H_
|
||||
|
||||
+2
-2
@@ -105,7 +105,7 @@ const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
|
||||
PortMap::InitOnce();
|
||||
FreeListElement::InitOnce();
|
||||
Api::InitOnce();
|
||||
CodeObservers::InitOnce();
|
||||
NOT_IN_PRODUCT(CodeObservers::InitOnce());
|
||||
if (FLAG_profiler) {
|
||||
ThreadInterrupter::InitOnce();
|
||||
Profiler::InitOnce();
|
||||
@@ -363,7 +363,7 @@ const char* Dart::Cleanup() {
|
||||
OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting code observers\n",
|
||||
timestamp());
|
||||
}
|
||||
CodeObservers::DeleteAll();
|
||||
NOT_IN_PRODUCT(CodeObservers::DeleteAll());
|
||||
if (FLAG_support_timeline) {
|
||||
if (FLAG_trace_shutdown) {
|
||||
OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down timeline\n",
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "vm/dart_api_state.h"
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/debugger.h"
|
||||
#include "vm/debuginfo.h"
|
||||
#include "vm/exceptions.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/growable_array.h"
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef VM_DEBUGINFO_H_
|
||||
#define VM_DEBUGINFO_H_
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/utils.h"
|
||||
#include "vm/globals.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// DebugInfo is used to generate minimal debug information containing code,
|
||||
// symbols, and line numbers for generated code in the dart VM. This information
|
||||
// can be used in two ways:
|
||||
// - for debugging using a debugger
|
||||
// - for generating information to be read by pprof to analyze Dart programs.
|
||||
class DebugInfo {
|
||||
public:
|
||||
// A basic ByteBuffer which is growable and uses malloc/free.
|
||||
class ByteBuffer {
|
||||
public:
|
||||
ByteBuffer() : size_(0), capacity_(0), data_(NULL) { }
|
||||
~ByteBuffer() {
|
||||
free(data_);
|
||||
size_ = 0;
|
||||
capacity_ = 0;
|
||||
data_ = NULL;
|
||||
}
|
||||
|
||||
uint8_t at(int index) const {
|
||||
ASSERT(0 <= index);
|
||||
ASSERT(index < size_);
|
||||
ASSERT(size_ <= capacity_);
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
uint8_t* data() const { return data_; }
|
||||
void set_data(uint8_t* value) { data_ = value; }
|
||||
int size() const { return size_; }
|
||||
|
||||
// Append an element.
|
||||
void Add(const uint8_t value) {
|
||||
Resize(size() + 1);
|
||||
data_[size() - 1] = value;
|
||||
}
|
||||
|
||||
private:
|
||||
void Resize(int new_size) {
|
||||
if (new_size > capacity_) {
|
||||
int new_capacity = Utils::RoundUpToPowerOfTwo(new_size);
|
||||
uint8_t* new_data =
|
||||
reinterpret_cast<uint8_t*>(realloc(data_, new_capacity));
|
||||
ASSERT(new_data != NULL);
|
||||
data_ = new_data;
|
||||
capacity_ = new_capacity;
|
||||
}
|
||||
size_ = new_size;
|
||||
}
|
||||
|
||||
int size_;
|
||||
int capacity_;
|
||||
uint8_t* data_;
|
||||
|
||||
// Disallow assignment
|
||||
DISALLOW_COPY_AND_ASSIGN(ByteBuffer);
|
||||
};
|
||||
|
||||
~DebugInfo();
|
||||
|
||||
// Add the code starting at pc.
|
||||
void AddCode(uword pc, intptr_t size);
|
||||
|
||||
// Add symbol information for a region (includes the start and end symbol),
|
||||
// does not add the actual code.
|
||||
void AddCodeRegion(const char* name, uword pc, intptr_t size);
|
||||
|
||||
// Write out all the debug information info the memory region.
|
||||
bool WriteToMemory(ByteBuffer* region);
|
||||
|
||||
// Create a new debug information generator.
|
||||
static DebugInfo* NewGenerator();
|
||||
|
||||
// Register this generated section with debuggger using the JIT interface.
|
||||
static void RegisterSection(const char* name,
|
||||
uword entry_point,
|
||||
intptr_t size);
|
||||
|
||||
// Unregister all generated section from debuggger.
|
||||
static void UnregisterAllSections();
|
||||
|
||||
private:
|
||||
void* handle_;
|
||||
DebugInfo();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DebugInfo);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_DEBUGINFO_H_
|
||||
@@ -1,77 +0,0 @@
|
||||
// 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 "vm/globals.h"
|
||||
#if defined(TARGET_OS_ANDROID)
|
||||
|
||||
#include "vm/debuginfo.h"
|
||||
|
||||
#include "vm/elfgen.h"
|
||||
#include "vm/gdbjit_android.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DebugInfo::DebugInfo() {
|
||||
handle_ = reinterpret_cast<void*>(new ElfGen());
|
||||
ASSERT(handle_ != NULL);
|
||||
}
|
||||
|
||||
|
||||
DebugInfo::~DebugInfo() {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
delete elf_gen;
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::AddCode(uword pc, intptr_t size) {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
elf_gen->AddCode(pc, size);
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::AddCodeRegion(const char* name, uword pc, intptr_t size) {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
elf_gen->AddCodeRegion(name, pc, size);
|
||||
}
|
||||
|
||||
|
||||
bool DebugInfo::WriteToMemory(ByteBuffer* region) {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
return elf_gen->WriteToMemory(region);
|
||||
}
|
||||
|
||||
|
||||
DebugInfo* DebugInfo::NewGenerator() {
|
||||
return new DebugInfo();
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::RegisterSection(const char* name,
|
||||
uword entry_point,
|
||||
intptr_t size) {
|
||||
ElfGen* elf_section = new ElfGen();
|
||||
ASSERT(elf_section != NULL);
|
||||
elf_section->AddCode(entry_point, size);
|
||||
elf_section->AddCodeRegion(name, entry_point, size);
|
||||
|
||||
ByteBuffer* dynamic_region = new ByteBuffer();
|
||||
ASSERT(dynamic_region != NULL);
|
||||
|
||||
elf_section->WriteToMemory(dynamic_region);
|
||||
|
||||
::addDynamicSection(reinterpret_cast<const char*>(dynamic_region->data()),
|
||||
dynamic_region->size());
|
||||
dynamic_region->set_data(NULL);
|
||||
delete dynamic_region;
|
||||
delete elf_section;
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::UnregisterAllSections() {
|
||||
::deleteDynamicSections();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_ANDROID)
|
||||
@@ -1,77 +0,0 @@
|
||||
// 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 "vm/globals.h"
|
||||
#if defined(TARGET_OS_LINUX)
|
||||
|
||||
#include "vm/debuginfo.h"
|
||||
|
||||
#include "vm/elfgen.h"
|
||||
#include "vm/gdbjit_linux.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DebugInfo::DebugInfo() {
|
||||
handle_ = reinterpret_cast<void*>(new ElfGen());
|
||||
ASSERT(handle_ != NULL);
|
||||
}
|
||||
|
||||
|
||||
DebugInfo::~DebugInfo() {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
delete elf_gen;
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::AddCode(uword pc, intptr_t size) {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
elf_gen->AddCode(pc, size);
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::AddCodeRegion(const char* name, uword pc, intptr_t size) {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
elf_gen->AddCodeRegion(name, pc, size);
|
||||
}
|
||||
|
||||
|
||||
bool DebugInfo::WriteToMemory(ByteBuffer* region) {
|
||||
ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
|
||||
return elf_gen->WriteToMemory(region);
|
||||
}
|
||||
|
||||
|
||||
DebugInfo* DebugInfo::NewGenerator() {
|
||||
return new DebugInfo();
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::RegisterSection(const char* name,
|
||||
uword entry_point,
|
||||
intptr_t size) {
|
||||
ElfGen* elf_section = new ElfGen();
|
||||
ASSERT(elf_section != NULL);
|
||||
elf_section->AddCode(entry_point, size);
|
||||
elf_section->AddCodeRegion(name, entry_point, size);
|
||||
|
||||
ByteBuffer* dynamic_region = new ByteBuffer();
|
||||
ASSERT(dynamic_region != NULL);
|
||||
|
||||
elf_section->WriteToMemory(dynamic_region);
|
||||
|
||||
::addDynamicSection(reinterpret_cast<const char*>(dynamic_region->data()),
|
||||
dynamic_region->size());
|
||||
dynamic_region->set_data(NULL);
|
||||
delete dynamic_region;
|
||||
delete elf_section;
|
||||
}
|
||||
|
||||
|
||||
void DebugInfo::UnregisterAllSections() {
|
||||
::deleteDynamicSections();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(TARGET_OS_LINUX)
|
||||
@@ -1,509 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef VM_ELFGEN_H_
|
||||
#define VM_ELFGEN_H_
|
||||
|
||||
#include "vm/lockers.h"
|
||||
#include "vm/os_thread.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of ElfGen
|
||||
//
|
||||
// Specification documents:
|
||||
// http://refspecs.freestandards.org
|
||||
//
|
||||
// ELF generic ABI:
|
||||
// http://refspecs.freestandards.org/elf/gabi4+/contents.html
|
||||
// ELF processor-specific supplement for X86_64:
|
||||
// http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf
|
||||
// DWARF 2.0:
|
||||
// http://refspecs.freestandards.org/dwarf/dwarf-2.0.0.pdf
|
||||
|
||||
// Forward declarations.
|
||||
class File;
|
||||
|
||||
// ElfGen is used to generate minimal ELF information containing code, symbols,
|
||||
// and line numbers for generated code in the dart VM. This information is
|
||||
// used in two ways:
|
||||
// - it is used to generate in-memory ELF information which is then
|
||||
// registered with gdb using the JIT interface.
|
||||
// - it is also used to generate a file with the ELF information. This file
|
||||
// is not executed, but read by pprof to analyze Dart programs.
|
||||
|
||||
class ElfGen {
|
||||
public:
|
||||
ElfGen();
|
||||
~ElfGen();
|
||||
|
||||
// Add the code starting at pc.
|
||||
void AddCode(uword pc, intptr_t size);
|
||||
|
||||
// Add symbol information for a region (includes the start and end symbol),
|
||||
// does not add the actual code.
|
||||
void AddCodeRegion(const char* name, uword pc, intptr_t size);
|
||||
|
||||
// Add specified symbol information, does not add the actual code.
|
||||
int AddFunction(const char* name, uword pc, intptr_t size);
|
||||
|
||||
// Write out all the Elf information using the specified handle.
|
||||
bool WriteToFile(File* handle);
|
||||
bool WriteToMemory(DebugInfo::ByteBuffer* region);
|
||||
|
||||
// Register this generated section with GDB using the JIT interface.
|
||||
static void RegisterSectionWithGDB(const char* name,
|
||||
uword entry_point,
|
||||
intptr_t size);
|
||||
|
||||
// Unregister all generated section from GDB.
|
||||
static void UnregisterAllSectionsWithGDB();
|
||||
|
||||
private:
|
||||
// ELF helpers
|
||||
typedef int (*OutputWriter)(void* handle,
|
||||
const DebugInfo::ByteBuffer& section);
|
||||
typedef void (*OutputPadder)(void* handle, int padding_size);
|
||||
|
||||
int AddString(DebugInfo::ByteBuffer* buf, const char* str);
|
||||
int AddSectionName(const char* str);
|
||||
int AddName(const char* str);
|
||||
void AddELFHeader(int shoff);
|
||||
void AddSectionHeader(int section, int offset);
|
||||
int PadSection(DebugInfo::ByteBuffer* section, int offset, int alignment);
|
||||
bool WriteOutput(void* handle, OutputWriter writer, OutputPadder padder);
|
||||
|
||||
uword text_vma_; // text section vma
|
||||
intptr_t text_size_; // text section size
|
||||
int text_padding_; // padding preceding text section
|
||||
|
||||
static const int kNumSections = 5; // we generate 5 sections
|
||||
int section_name_[kNumSections]; // array of section name indices
|
||||
DebugInfo::ByteBuffer section_buf_[kNumSections]; // array of section buffers
|
||||
DebugInfo::ByteBuffer header_; // ELF header buffer
|
||||
DebugInfo::ByteBuffer sheaders_; // section header table buffer
|
||||
DebugInfo::ByteBuffer lineprog_; // line statement program, part of
|
||||
// '.debug_line' section
|
||||
|
||||
// current state of the DWARF line info generator
|
||||
uintptr_t cur_addr_; // current pc
|
||||
int map_offset_;
|
||||
uword map_begin_;
|
||||
uword map_end_;
|
||||
|
||||
Mutex lock_;
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
// Various constant sizes for ELF files.
|
||||
kAddrSize = sizeof(uword),
|
||||
kPageSize = 4*1024, // Memory mapping page size.
|
||||
kTextAlign = 16,
|
||||
kELFHeaderSize = 40 + 3*kAddrSize,
|
||||
kProgramHeaderEntrySize = 8 + 6*kAddrSize,
|
||||
kSectionHeaderEntrySize = 16 + 6*kAddrSize,
|
||||
kSymbolSize = 8 + 2*kAddrSize,
|
||||
|
||||
// Our own layout of sections.
|
||||
kUndef = 0, // Undefined section.
|
||||
kText, // Text section.
|
||||
kShStrtab, // Section header string table.
|
||||
kStrtab, // String table.
|
||||
kSymtab, // Symbol table.
|
||||
kNumSections, // Num of section header entries in section header table.
|
||||
|
||||
// Various ELF constants.
|
||||
kELFCLASS32 = 1,
|
||||
kELFCLASS64 = 2,
|
||||
kELFDATA2LSB = 1,
|
||||
kELFDATA2MSB = 2,
|
||||
kEM_386 = 3,
|
||||
kEM_MIPS = 8,
|
||||
kEM_ARM = 40,
|
||||
kEM_X86_64 = 62,
|
||||
kEV_CURRENT = 1,
|
||||
kET_EXEC = 2, // not used
|
||||
kET_DYN = 3,
|
||||
kSHT_PROGBITS = 1,
|
||||
kSHT_SYMTAB = 2,
|
||||
kSHT_STRTAB = 3,
|
||||
kSHF_WRITE = 1, // not used
|
||||
kSHF_ALLOC = 2,
|
||||
kSHF_EXECINSTR = 4,
|
||||
kSTB_LOCAL = 0,
|
||||
kSTB_EXPORTED = 1,
|
||||
kSTT_FUNC = 2,
|
||||
};
|
||||
|
||||
|
||||
// ELF and DWARF constants.
|
||||
static const char* kEI_MAG0_MAG3 = "\177ELF";
|
||||
static const uint8_t kSpecialOpcodeLengths[] = { 0, 1, 1, 1, 1, 0, 0, 0, 1 };
|
||||
|
||||
|
||||
// Section attributes.
|
||||
// The field names correspond to the field names of Elf32_Shdr and Elf64_Shdr.
|
||||
static const struct {
|
||||
// Section header index (only used to check correct section order).
|
||||
int shndx;
|
||||
const char* name; // sh_name will be the index of name inserted in shstrtab.
|
||||
int sh_type;
|
||||
int sh_flags;
|
||||
int sh_link;
|
||||
int sh_addralign;
|
||||
int sh_entsize;
|
||||
} section_attr[kNumSections + 1] = {
|
||||
{ kUndef, "", 0, 0,
|
||||
0, 0, 0 },
|
||||
{ kText, ".text", kSHT_PROGBITS, kSHF_ALLOC|kSHF_EXECINSTR,
|
||||
0, kTextAlign, 0 },
|
||||
{ kShStrtab, ".shstrtab", kSHT_STRTAB, 0,
|
||||
0, 1, 0 },
|
||||
{ kStrtab, ".strtab", kSHT_STRTAB, 0,
|
||||
0, 1, 0 },
|
||||
{ kSymtab, ".symtab", kSHT_SYMTAB, 0,
|
||||
kStrtab, kAddrSize, kSymbolSize },
|
||||
// Sentinel to pad the last section
|
||||
// for proper alignment of section header table.
|
||||
{ 0, "", 0, 0,
|
||||
0, kAddrSize, 0 }
|
||||
};
|
||||
|
||||
|
||||
// Convenience function aligning an integer.
|
||||
static inline uintptr_t Align(uintptr_t x, intptr_t size) {
|
||||
// size is a power of 2
|
||||
ASSERT((size & (size-1)) == 0);
|
||||
return (x + (size-1)) & ~(size-1);
|
||||
}
|
||||
|
||||
|
||||
// Convenience function writing a single byte to a ByteBuffer.
|
||||
static inline void WriteByte(DebugInfo::ByteBuffer* buf, uint8_t byte) {
|
||||
buf->Add(byte);
|
||||
}
|
||||
|
||||
|
||||
// Convenience function writing an unsigned native word to a ByteBuffer.
|
||||
// The word is 32-bit wide in 32-bit mode and 64-bit wide in 64-bit mode.
|
||||
static inline void WriteWord(DebugInfo::ByteBuffer* buf, uword word) {
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(&word);
|
||||
for (size_t i = 0; i < sizeof(word); i++) {
|
||||
buf->Add(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void WriteInt(DebugInfo::ByteBuffer* buf, int word) {
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(&word);
|
||||
for (size_t i = 0; i < sizeof(word); i++) {
|
||||
buf->Add(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void WriteShort(DebugInfo::ByteBuffer* buf, uint16_t word) {
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(&word);
|
||||
for (size_t i = 0; i < sizeof(word); i++) {
|
||||
buf->Add(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void WriteString(DebugInfo::ByteBuffer* buf, const char* str) {
|
||||
for (size_t i = 0; i < strlen(str); i++) {
|
||||
buf->Add(static_cast<uint8_t>(str[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void Write(DebugInfo::ByteBuffer* buf,
|
||||
const void* mem,
|
||||
int length) {
|
||||
const uint8_t* p = reinterpret_cast<const uint8_t*>(mem);
|
||||
for (int i = 0; i < length; i++) {
|
||||
buf->Add(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write given section to file and return written size.
|
||||
static int WriteSectionToFile(void* handle,
|
||||
const DebugInfo::ByteBuffer& section) {
|
||||
#if 0
|
||||
File* fp = reinterpret_cast<File*>(handle);
|
||||
int size = section.size();
|
||||
fp->WriteFully(section.data(), size);
|
||||
return size;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Pad output file to specified padding size.
|
||||
static void PadFile(void* handle, int padding_size) {
|
||||
#if 0
|
||||
File* fp = reinterpret_cast<File*>(handle);
|
||||
for (int i = 0; i < padding_size; i++) {
|
||||
fp->WriteFully("", 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Write given section to specified memory region and return written size.
|
||||
static int WriteSectionToMemory(void* handle,
|
||||
const DebugInfo::ByteBuffer& section) {
|
||||
DebugInfo::ByteBuffer* buffer =
|
||||
reinterpret_cast<DebugInfo::ByteBuffer*>(handle);
|
||||
int size = section.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
buffer->Add(static_cast<uint8_t>(section.data()[i]));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
// Pad memory to specified padding size.
|
||||
static void PadMemory(void* handle, int padding_size) {
|
||||
DebugInfo::ByteBuffer* buffer =
|
||||
reinterpret_cast<DebugInfo::ByteBuffer*>(handle);
|
||||
for (int i = 0; i < padding_size; i++) {
|
||||
buffer->Add(static_cast<uint8_t>(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Constructor
|
||||
ElfGen::ElfGen()
|
||||
: text_vma_(0), text_size_(0), text_padding_(0), map_offset_(0), lock_() {
|
||||
for (int i = 0; i < kNumSections; i++) {
|
||||
ASSERT(section_attr[i].shndx == i); // Verify layout of sections.
|
||||
section_name_[i] = AddSectionName(section_attr[i].name);
|
||||
}
|
||||
// Section header string table always starts with an empty string, which is
|
||||
// the name of the kUndef section.
|
||||
ASSERT((section_attr[0].name[0] == '\0') && (section_name_[0] == 0));
|
||||
|
||||
// String table always starts with an empty string.
|
||||
AddName("");
|
||||
ASSERT(section_buf_[kStrtab].size() == 1);
|
||||
|
||||
// Symbol at index 0 in symtab is always STN_UNDEF (all zero):
|
||||
DebugInfo::ByteBuffer* symtab = §ion_buf_[kSymtab];
|
||||
while (symtab->size() < kSymbolSize) {
|
||||
WriteInt(symtab, 0);
|
||||
}
|
||||
ASSERT(symtab->size() == kSymbolSize);
|
||||
}
|
||||
|
||||
|
||||
// Destructor
|
||||
ElfGen::~ElfGen() {
|
||||
}
|
||||
|
||||
|
||||
void ElfGen::AddCode(uword pc, intptr_t size) {
|
||||
MutexLocker ml(&lock_);
|
||||
text_vma_ = pc;
|
||||
text_size_ = size;
|
||||
// We pad the text section in the file to align absolute code addresses with
|
||||
// corresponding file offsets as if the code had been loaded by memory
|
||||
// mapping.
|
||||
if (text_vma_ % kPageSize < kELFHeaderSize) {
|
||||
text_padding_ = text_vma_ % kPageSize + kPageSize - kELFHeaderSize;
|
||||
} else {
|
||||
text_padding_ = text_vma_ % kPageSize - kELFHeaderSize;
|
||||
}
|
||||
|
||||
Write(§ion_buf_[kText], reinterpret_cast<void*>(pc), size);
|
||||
// map_offset is the file offset of the first mapped page.
|
||||
map_offset_ = (kELFHeaderSize + text_padding_)/kPageSize*kPageSize;
|
||||
map_begin_ = Align(text_vma_ - kPageSize + 1, kPageSize);
|
||||
map_end_ = Align(text_vma_ + size, kPageSize);
|
||||
}
|
||||
|
||||
|
||||
void ElfGen::AddCodeRegion(const char* name, uword pc, intptr_t size) {
|
||||
MutexLocker ml(&lock_);
|
||||
AddFunction(name, pc, size);
|
||||
char end_name[256];
|
||||
OS::SNPrint(end_name, sizeof(end_name), "%s_end", name);
|
||||
AddFunction(end_name, pc + size, 0);
|
||||
}
|
||||
|
||||
|
||||
int ElfGen::AddFunction(const char* name, uword pc, intptr_t size) {
|
||||
ASSERT(text_vma_ != 0); // code must have been added
|
||||
DebugInfo::ByteBuffer* symtab = §ion_buf_[kSymtab];
|
||||
const int beg = symtab->size();
|
||||
WriteInt(symtab, AddName(name)); // st_name
|
||||
#if defined(ARCH_IS_64_BIT)
|
||||
WriteShort(symtab, (kSTB_LOCAL << 4) + kSTT_FUNC); // st_info + (st_other<<8)
|
||||
WriteShort(symtab, kText); // st_shndx
|
||||
#endif
|
||||
WriteWord(symtab, pc); // st_value
|
||||
WriteWord(symtab, size); // st_size
|
||||
#if defined(ARCH_IS_32_BIT)
|
||||
// st_info + (st_other<<8)
|
||||
WriteShort(symtab, (kSTB_EXPORTED << 4) + kSTT_FUNC);
|
||||
WriteShort(symtab, kText); // st_shndx
|
||||
#endif
|
||||
ASSERT(symtab->size() - beg == kSymbolSize);
|
||||
return beg / kSymbolSize; // symbol index in symtab
|
||||
}
|
||||
|
||||
|
||||
bool ElfGen::WriteToFile(File* handle) {
|
||||
return WriteOutput(handle, WriteSectionToFile, PadFile);
|
||||
}
|
||||
|
||||
|
||||
bool ElfGen::WriteToMemory(DebugInfo::ByteBuffer* region) {
|
||||
return WriteOutput(region, WriteSectionToMemory, PadMemory);
|
||||
}
|
||||
|
||||
|
||||
int ElfGen::AddString(DebugInfo::ByteBuffer* buf, const char* str) {
|
||||
const int str_index = buf->size();
|
||||
WriteString(buf, str);
|
||||
WriteByte(buf, 0); // terminating '\0'
|
||||
return str_index;
|
||||
}
|
||||
|
||||
|
||||
int ElfGen::AddSectionName(const char* str) {
|
||||
return AddString(§ion_buf_[kShStrtab], str);
|
||||
}
|
||||
|
||||
|
||||
int ElfGen::AddName(const char* str) {
|
||||
return AddString(§ion_buf_[kStrtab], str);
|
||||
}
|
||||
|
||||
|
||||
void ElfGen::AddELFHeader(int shoff) {
|
||||
ASSERT(text_vma_ != 0); // Code must have been added.
|
||||
Write(&header_, kEI_MAG0_MAG3, 4); // EI_MAG0..EI_MAG3
|
||||
#if defined(ARCH_IS_32_BIT)
|
||||
WriteByte(&header_, kELFCLASS32); // EI_CLASS
|
||||
#elif defined(ARCH_IS_64_BIT)
|
||||
WriteByte(&header_, kELFCLASS64); // EI_CLASS
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
WriteByte(&header_, kELFDATA2LSB); // EI_DATA
|
||||
WriteByte(&header_, kEV_CURRENT); // EI_VERSION
|
||||
WriteByte(&header_, 0); // EI_PAD
|
||||
WriteInt(&header_, 0); // EI_PAD
|
||||
WriteInt(&header_, 0); // EI_PAD
|
||||
WriteShort(&header_, kET_DYN); // e_type, fake a shared object.
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
WriteShort(&header_, kEM_386); // e_machine
|
||||
#elif defined(TARGET_ARCH_X64)
|
||||
WriteShort(&header_, kEM_X86_64); // e_machine
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
WriteShort(&header_, kEM_ARM); // e_machine
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
// TODO(zra): Find the right ARM64 constant.
|
||||
WriteShort(&header_, kEM_ARM); // e_machine
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
WriteShort(&header_, kEM_MIPS); // e_machine
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
WriteInt(&header_, kEV_CURRENT); // e_version
|
||||
WriteWord(&header_, 0); // e_entry: none
|
||||
WriteWord(&header_, 0); // e_phoff: no program header table.
|
||||
WriteWord(&header_, shoff); // e_shoff: section header table offset.
|
||||
WriteInt(&header_, 0); // e_flags: no flags.
|
||||
WriteShort(&header_, kELFHeaderSize); // e_ehsize: header size.
|
||||
WriteShort(&header_, kProgramHeaderEntrySize); // e_phentsize
|
||||
WriteShort(&header_, 0); // e_phnum: no entries program header table.
|
||||
WriteShort(&header_, kSectionHeaderEntrySize); // e_shentsize
|
||||
// e_shnum: number of section header entries.
|
||||
WriteShort(&header_, kNumSections);
|
||||
WriteShort(&header_, kShStrtab); // e_shstrndx: index of shstrtab.
|
||||
ASSERT(header_.size() == kELFHeaderSize);
|
||||
}
|
||||
|
||||
|
||||
void ElfGen::AddSectionHeader(int section, int offset) {
|
||||
WriteInt(&sheaders_, section_name_[section]);
|
||||
WriteInt(&sheaders_, section_attr[section].sh_type);
|
||||
WriteWord(&sheaders_, section_attr[section].sh_flags);
|
||||
// sh_addr: abs addr
|
||||
WriteWord(&sheaders_, (section == kText) ? text_vma_ : 0);
|
||||
WriteWord(&sheaders_, offset); // sh_offset: section file offset.
|
||||
WriteWord(&sheaders_, section_buf_[section].size());
|
||||
WriteInt(&sheaders_, section_attr[section].sh_link);
|
||||
WriteInt(&sheaders_, 0);
|
||||
WriteWord(&sheaders_, section_attr[section].sh_addralign);
|
||||
WriteWord(&sheaders_, section_attr[section].sh_entsize);
|
||||
ASSERT(sheaders_.size() == kSectionHeaderEntrySize * (section + 1));
|
||||
}
|
||||
|
||||
|
||||
// Pads the given section with zero bytes for the given aligment, assuming the
|
||||
// section starts at given file offset; returns file offset after padded
|
||||
// section.
|
||||
int ElfGen::PadSection(DebugInfo::ByteBuffer* section,
|
||||
int offset,
|
||||
int alignment) {
|
||||
offset += section->size();
|
||||
int aligned_offset = Align(offset, alignment);
|
||||
while (offset++ < aligned_offset) {
|
||||
WriteByte(section, 0); // one byte padding.
|
||||
}
|
||||
return aligned_offset;
|
||||
}
|
||||
|
||||
|
||||
bool ElfGen::WriteOutput(void* handle,
|
||||
OutputWriter writer,
|
||||
OutputPadder padder) {
|
||||
if (handle == NULL || writer == NULL || padder == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Align all sections before writing the ELF header in order to calculate the
|
||||
// file offset of the section header table, which is needed in the ELF header.
|
||||
// Pad each section as required by the aligment constraint of the immediately
|
||||
// following section, except the ELF header section, which requires special
|
||||
// padding (text_padding_) to align the text_ section.
|
||||
int offset = kELFHeaderSize + text_padding_;
|
||||
for (int i = kText; i < kNumSections; i++) {
|
||||
offset = PadSection(§ion_buf_[i],
|
||||
offset,
|
||||
section_attr[i+1].sh_addralign);
|
||||
}
|
||||
|
||||
const int shoff = offset; // Section header table offset.
|
||||
|
||||
// Write elf header.
|
||||
AddELFHeader(shoff);
|
||||
offset = (*writer)(handle, header_);
|
||||
|
||||
// Pad file before writing text section in order to align vma with file
|
||||
// offset.
|
||||
(*padder)(handle, text_padding_);
|
||||
|
||||
offset += text_padding_;
|
||||
ASSERT((text_vma_ - offset) % kPageSize == 0);
|
||||
|
||||
// Section header at index 0 in section header table is always SHN_UNDEF:
|
||||
for (int i = 0; i < kNumSections; i++) {
|
||||
AddSectionHeader(i, offset);
|
||||
offset += (*writer)(handle, section_buf_[i]);
|
||||
}
|
||||
// Write section header table.
|
||||
ASSERT(offset == shoff);
|
||||
offset += (*writer)(handle, sheaders_);
|
||||
ASSERT(offset == shoff + kNumSections * kSectionHeaderEntrySize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_ELFGEN_H_
|
||||
@@ -38,6 +38,8 @@ R(profiler, false, bool, true, \
|
||||
"Enable the profiler.") \
|
||||
R(support_ast_printer, false, bool, true, \
|
||||
"Support the AST printer.") \
|
||||
R(support_compiler_stats, false, bool, true, \
|
||||
"Support compiler stats.") \
|
||||
R(support_debugger, false, bool, true, \
|
||||
"Support the debugger.") \
|
||||
R(support_disassembler, false, bool, true, \
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "vm/intermediate_language.h"
|
||||
#include "vm/growable_array.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/report.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
// 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 "vm/globals.h"
|
||||
#if defined(TARGET_OS_ANDROID)
|
||||
|
||||
#include <stdint.h> // NOLINT
|
||||
#include <stdio.h> // NOLINT
|
||||
#include <stdlib.h> // NOLINT
|
||||
|
||||
#include "vm/gdbjit_android.h"
|
||||
|
||||
extern "C" {
|
||||
typedef enum {
|
||||
JIT_NOACTION = 0,
|
||||
JIT_REGISTER_FN,
|
||||
JIT_UNREGISTER_FN
|
||||
} jit_actions_t;
|
||||
|
||||
struct jit_code_entry {
|
||||
struct jit_code_entry* next_entry;
|
||||
struct jit_code_entry* prev_entry;
|
||||
const char* symfile_addr;
|
||||
uint64_t symfile_size;
|
||||
};
|
||||
|
||||
struct jit_descriptor {
|
||||
uint32_t version;
|
||||
/* This type should be jit_actions_t, but we use uint32_t
|
||||
to be explicit about the bitwidth. */
|
||||
uint32_t action_flag;
|
||||
struct jit_code_entry* relevant_entry;
|
||||
struct jit_code_entry* first_entry;
|
||||
};
|
||||
|
||||
#ifndef GDB_JIT_SYMBOLS
|
||||
/* GDB puts a breakpoint in this function. */
|
||||
void __attribute__((noinline)) __jit_debug_register_code() { }
|
||||
|
||||
/* Make sure to specify the version statically, because the
|
||||
debugger may check the version before we can set it. */
|
||||
struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
|
||||
#endif
|
||||
|
||||
static struct jit_code_entry* first_dynamic_region = NULL;
|
||||
static struct jit_code_entry* last_dynamic_region = NULL;
|
||||
|
||||
void addDynamicSection(const char* symfile_addr, uint64_t symfile_size) {
|
||||
jit_code_entry* new_entry = reinterpret_cast<jit_code_entry*>(
|
||||
malloc(sizeof(jit_code_entry)));
|
||||
if (new_entry != NULL) {
|
||||
new_entry->symfile_addr = symfile_addr;
|
||||
new_entry->symfile_size = symfile_size;
|
||||
new_entry->next_entry = NULL;
|
||||
new_entry->prev_entry = last_dynamic_region;
|
||||
if (first_dynamic_region == NULL) {
|
||||
first_dynamic_region = new_entry;
|
||||
} else {
|
||||
last_dynamic_region->next_entry = new_entry;
|
||||
}
|
||||
last_dynamic_region = new_entry;
|
||||
}
|
||||
__jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
|
||||
__jit_debug_descriptor.relevant_entry = new_entry;
|
||||
__jit_debug_descriptor.first_entry = first_dynamic_region;
|
||||
__jit_debug_register_code();
|
||||
}
|
||||
|
||||
void deleteDynamicSections() {
|
||||
struct jit_code_entry* iterator = last_dynamic_region;
|
||||
while (iterator != NULL) {
|
||||
__jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
|
||||
__jit_debug_descriptor.relevant_entry = iterator;
|
||||
__jit_debug_descriptor.first_entry = first_dynamic_region;
|
||||
__jit_debug_register_code();
|
||||
iterator = iterator->prev_entry;
|
||||
}
|
||||
first_dynamic_region = NULL;
|
||||
last_dynamic_region = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // defined(TARGET_OS_ANDROID)
|
||||
@@ -1,15 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef VM_GDBJIT_ANDROID_H_
|
||||
#define VM_GDBJIT_ANDROID_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
void addDynamicSection(const char* symfile_addr, uint64_t symfile_size);
|
||||
void deleteDynamicSections();
|
||||
};
|
||||
|
||||
#endif // VM_GDBJIT_ANDROID_H_
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright (c) 2011, 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 "vm/globals.h"
|
||||
#if defined(TARGET_OS_LINUX)
|
||||
|
||||
#include <stdint.h> // NOLINT
|
||||
#include <stdio.h> // NOLINT
|
||||
#include <stdlib.h> // NOLINT
|
||||
|
||||
#include "vm/gdbjit_linux.h"
|
||||
|
||||
extern "C" {
|
||||
typedef enum {
|
||||
JIT_NOACTION = 0,
|
||||
JIT_REGISTER_FN,
|
||||
JIT_UNREGISTER_FN
|
||||
} jit_actions_t;
|
||||
|
||||
struct jit_code_entry {
|
||||
struct jit_code_entry* next_entry;
|
||||
struct jit_code_entry* prev_entry;
|
||||
const char* symfile_addr;
|
||||
uint64_t symfile_size;
|
||||
};
|
||||
|
||||
struct jit_descriptor {
|
||||
uint32_t version;
|
||||
/* This type should be jit_actions_t, but we use uint32_t
|
||||
to be explicit about the bitwidth. */
|
||||
uint32_t action_flag;
|
||||
struct jit_code_entry* relevant_entry;
|
||||
struct jit_code_entry* first_entry;
|
||||
};
|
||||
|
||||
#ifndef GDB_JIT_SYMBOLS
|
||||
/* GDB puts a breakpoint in this function. */
|
||||
void __attribute__((noinline)) __jit_debug_register_code() { }
|
||||
|
||||
/* Make sure to specify the version statically, because the
|
||||
debugger may check the version before we can set it. */
|
||||
struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
|
||||
#endif
|
||||
|
||||
static struct jit_code_entry* first_dynamic_region = NULL;
|
||||
static struct jit_code_entry* last_dynamic_region = NULL;
|
||||
|
||||
void addDynamicSection(const char* symfile_addr, uint64_t symfile_size) {
|
||||
jit_code_entry* new_entry = reinterpret_cast<jit_code_entry*>(
|
||||
malloc(sizeof(jit_code_entry)));
|
||||
if (new_entry != NULL) {
|
||||
new_entry->symfile_addr = symfile_addr;
|
||||
new_entry->symfile_size = symfile_size;
|
||||
new_entry->next_entry = NULL;
|
||||
new_entry->prev_entry = last_dynamic_region;
|
||||
if (first_dynamic_region == NULL) {
|
||||
first_dynamic_region = new_entry;
|
||||
} else {
|
||||
last_dynamic_region->next_entry = new_entry;
|
||||
}
|
||||
last_dynamic_region = new_entry;
|
||||
}
|
||||
__jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
|
||||
__jit_debug_descriptor.relevant_entry = new_entry;
|
||||
__jit_debug_descriptor.first_entry = first_dynamic_region;
|
||||
__jit_debug_register_code();
|
||||
}
|
||||
|
||||
void deleteDynamicSections() {
|
||||
struct jit_code_entry* iterator = last_dynamic_region;
|
||||
while (iterator != NULL) {
|
||||
__jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
|
||||
__jit_debug_descriptor.relevant_entry = iterator;
|
||||
__jit_debug_descriptor.first_entry = first_dynamic_region;
|
||||
__jit_debug_register_code();
|
||||
iterator = iterator->prev_entry;
|
||||
}
|
||||
first_dynamic_region = NULL;
|
||||
last_dynamic_region = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // defined(TARGET_OS_LINUX)
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright (c) 2011, 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 VM_GDBJIT_LINUX_H_
|
||||
#define VM_GDBJIT_LINUX_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
void addDynamicSection(const char* symfile_addr, uint64_t symfile_size);
|
||||
void deleteDynamicSections();
|
||||
};
|
||||
|
||||
#endif // VM_GDBJIT_LINUX_H_
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/debugger.h"
|
||||
#include "vm/deopt_instructions.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/heap.h"
|
||||
#include "vm/lockers.h"
|
||||
#include "vm/log.h"
|
||||
@@ -821,7 +822,6 @@ Isolate::Isolate(const Dart_IsolateFlags& api_flags)
|
||||
last_allocationprofile_accumulator_reset_timestamp_(0),
|
||||
last_allocationprofile_gc_timestamp_(0),
|
||||
object_id_ring_(NULL),
|
||||
trace_buffer_(NULL),
|
||||
tag_table_(GrowableObjectArray::null()),
|
||||
deoptimized_code_array_(GrowableObjectArray::null()),
|
||||
background_compiler_(NULL),
|
||||
@@ -962,9 +962,11 @@ Isolate* Isolate::Init(const char* name_prefix,
|
||||
}
|
||||
}
|
||||
|
||||
result->compiler_stats_ = new CompilerStats(result);
|
||||
if (FLAG_compiler_benchmark) {
|
||||
result->compiler_stats_->EnableBenchmark();
|
||||
if (FLAG_support_compiler_stats) {
|
||||
result->compiler_stats_ = new CompilerStats(result);
|
||||
if (FLAG_compiler_benchmark) {
|
||||
result->compiler_stats_->EnableBenchmark();
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_support_service) {
|
||||
@@ -1776,7 +1778,7 @@ void Isolate::Shutdown() {
|
||||
}
|
||||
|
||||
// Write compiler stats data if enabled.
|
||||
if (FLAG_compiler_stats
|
||||
if (FLAG_support_compiler_stats && FLAG_compiler_stats
|
||||
&& !ServiceIsolate::IsServiceIsolateDescendant(this)
|
||||
&& (this != Dart::vm_isolate())) {
|
||||
OS::Print("%s", compiler_stats()->PrintToZone());
|
||||
|
||||
+1
-11
@@ -19,7 +19,7 @@
|
||||
#include "vm/os_thread.h"
|
||||
#include "vm/timeline.h"
|
||||
#include "vm/timer.h"
|
||||
#include "vm/trace_buffer.h"
|
||||
#include "vm/token_position.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
@@ -494,13 +494,6 @@ class Isolate : public BaseIsolate {
|
||||
return object_id_ring_;
|
||||
}
|
||||
|
||||
void set_trace_buffer(TraceBuffer* buffer) {
|
||||
trace_buffer_ = buffer;
|
||||
}
|
||||
TraceBuffer* trace_buffer() {
|
||||
return trace_buffer_;
|
||||
}
|
||||
|
||||
DeoptContext* deopt_context() const { return deopt_context_; }
|
||||
void set_deopt_context(DeoptContext* value) {
|
||||
ASSERT(value == NULL || deopt_context_ == NULL);
|
||||
@@ -809,9 +802,6 @@ class Isolate : public BaseIsolate {
|
||||
// Ring buffer of objects assigned an id.
|
||||
ObjectIdRing* object_id_ring_;
|
||||
|
||||
// Trace buffer support.
|
||||
TraceBuffer* trace_buffer_;
|
||||
|
||||
VMTagCounters vm_tag_counters_;
|
||||
RawGrowableObjectArray* tag_table_;
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "vm/parser.h"
|
||||
#include "vm/precompiler.h"
|
||||
#include "vm/profiler.h"
|
||||
#include "vm/report.h"
|
||||
#include "vm/reusable_handles.h"
|
||||
#include "vm/runtime_entry.h"
|
||||
#include "vm/scopes.h"
|
||||
@@ -12848,11 +12847,13 @@ RawCode* Code::FinalizeCode(const char* name,
|
||||
CPU::FlushICache(instrs.EntryPoint(), instrs.size());
|
||||
|
||||
code.set_compile_timestamp(OS::GetCurrentMonotonicMicros());
|
||||
#ifndef PRODUCT
|
||||
CodeObservers::NotifyAll(name,
|
||||
instrs.EntryPoint(),
|
||||
assembler->prologue_offset(),
|
||||
instrs.size(),
|
||||
optimized);
|
||||
#endif
|
||||
{
|
||||
NoSafepointScope no_safepoint;
|
||||
const ZoneGrowableArray<intptr_t>& pointer_offsets =
|
||||
@@ -12909,13 +12910,14 @@ RawCode* Code::FinalizeCode(const Function& function,
|
||||
bool optimized) {
|
||||
// Calling ToLibNamePrefixedQualifiedCString is very expensive,
|
||||
// try to avoid it.
|
||||
#ifndef PRODUCT
|
||||
if (CodeObservers::AreActive()) {
|
||||
return FinalizeCode(function.ToLibNamePrefixedQualifiedCString(),
|
||||
assembler,
|
||||
optimized);
|
||||
} else {
|
||||
return FinalizeCode("", assembler, optimized);
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
return FinalizeCode("", assembler, optimized);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,9 +21,7 @@
|
||||
#include "platform/utils.h"
|
||||
#include "vm/code_observers.h"
|
||||
#include "vm/dart.h"
|
||||
#include "vm/debuginfo.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/vtune.h"
|
||||
#include "vm/zone.h"
|
||||
|
||||
|
||||
@@ -31,12 +29,11 @@ namespace dart {
|
||||
|
||||
// Android CodeObservers.
|
||||
|
||||
DEFINE_FLAG(bool, generate_gdb_symbols, false,
|
||||
"Generate symbols of generated dart functions for debugging with GDB");
|
||||
#ifndef PRODUCT
|
||||
|
||||
DEFINE_FLAG(bool, generate_perf_events_symbols, false,
|
||||
"Generate events symbols for profiling with perf");
|
||||
|
||||
|
||||
class PerfCodeObserver : public CodeObserver {
|
||||
public:
|
||||
PerfCodeObserver() : out_file_(NULL) {
|
||||
@@ -83,41 +80,7 @@ class PerfCodeObserver : public CodeObserver {
|
||||
DISALLOW_COPY_AND_ASSIGN(PerfCodeObserver);
|
||||
};
|
||||
|
||||
|
||||
class GdbCodeObserver : public CodeObserver {
|
||||
public:
|
||||
GdbCodeObserver() { }
|
||||
|
||||
virtual bool IsActive() const {
|
||||
return FLAG_generate_gdb_symbols;
|
||||
}
|
||||
|
||||
virtual void Notify(const char* name,
|
||||
uword base,
|
||||
uword prologue_offset,
|
||||
uword size,
|
||||
bool optimized) {
|
||||
if (prologue_offset > 0) {
|
||||
// In order to ensure that gdb sees the first instruction of a function
|
||||
// as the prologue sequence we register two symbols for the cases when
|
||||
// the prologue sequence is not the first instruction:
|
||||
// <name>_entry is used for code preceding the prologue sequence.
|
||||
// <name> for rest of the code (first instruction is prologue sequence).
|
||||
char* pname = OS::SCreate(Thread::Current()->zone(),
|
||||
"%s_%s", name, "entry");
|
||||
DebugInfo::RegisterSection(pname, base, size);
|
||||
DebugInfo::RegisterSection(name,
|
||||
(base + prologue_offset),
|
||||
(size - prologue_offset));
|
||||
} else {
|
||||
DebugInfo::RegisterSection(name, base, size);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(GdbCodeObserver);
|
||||
};
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
const char* OS::Name() {
|
||||
return "android";
|
||||
@@ -427,15 +390,11 @@ bool OS::StringToInt64(const char* str, int64_t* value) {
|
||||
|
||||
|
||||
void OS::RegisterCodeObservers() {
|
||||
#ifndef PRODUCT
|
||||
if (FLAG_generate_perf_events_symbols) {
|
||||
CodeObservers::Register(new PerfCodeObserver);
|
||||
}
|
||||
if (FLAG_generate_gdb_symbols) {
|
||||
CodeObservers::Register(new GdbCodeObserver);
|
||||
}
|
||||
#if defined(DART_VTUNE_SUPPORT)
|
||||
CodeObservers::Register(new VTuneCodeObserver);
|
||||
#endif
|
||||
#endif // !PRODUCT
|
||||
}
|
||||
|
||||
|
||||
|
||||
+6
-260
@@ -22,26 +22,21 @@
|
||||
#include "platform/utils.h"
|
||||
#include "vm/code_observers.h"
|
||||
#include "vm/dart.h"
|
||||
#include "vm/debuginfo.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/lockers.h"
|
||||
#include "vm/os_thread.h"
|
||||
#include "vm/vtune.h"
|
||||
#include "vm/zone.h"
|
||||
|
||||
|
||||
namespace dart {
|
||||
|
||||
// Linux CodeObservers.
|
||||
#ifndef PRODUCT
|
||||
|
||||
DEFINE_FLAG(bool, generate_gdb_symbols, false,
|
||||
"Generate symbols of generated dart functions for debugging with GDB");
|
||||
DEFINE_FLAG(bool, generate_perf_events_symbols, false,
|
||||
"Generate events symbols for profiling with perf");
|
||||
DEFINE_FLAG(bool, generate_perf_jitdump, false,
|
||||
"Writes jitdump data for profiling with perf annotate");
|
||||
|
||||
|
||||
// Linux CodeObservers.
|
||||
class PerfCodeObserver : public CodeObserver {
|
||||
public:
|
||||
PerfCodeObserver() : out_file_(NULL) {
|
||||
@@ -92,249 +87,7 @@ class PerfCodeObserver : public CodeObserver {
|
||||
};
|
||||
|
||||
|
||||
class GdbCodeObserver : public CodeObserver {
|
||||
public:
|
||||
GdbCodeObserver() { }
|
||||
|
||||
virtual bool IsActive() const {
|
||||
return FLAG_generate_gdb_symbols;
|
||||
}
|
||||
|
||||
virtual void Notify(const char* name,
|
||||
uword base,
|
||||
uword prologue_offset,
|
||||
uword size,
|
||||
bool optimized) {
|
||||
if (prologue_offset > 0) {
|
||||
// In order to ensure that gdb sees the first instruction of a function
|
||||
// as the prologue sequence we register two symbols for the cases when
|
||||
// the prologue sequence is not the first instruction:
|
||||
// <name>_entry is used for code preceding the prologue sequence.
|
||||
// <name> for rest of the code (first instruction is prologue sequence).
|
||||
char* pname = OS::SCreate(Thread::Current()->zone(),
|
||||
"%s_%s", name, "entry");
|
||||
DebugInfo::RegisterSection(pname, base, size);
|
||||
DebugInfo::RegisterSection(name,
|
||||
(base + prologue_offset),
|
||||
(size - prologue_offset));
|
||||
} else {
|
||||
DebugInfo::RegisterSection(name, base, size);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(GdbCodeObserver);
|
||||
};
|
||||
|
||||
|
||||
#define CLOCKFD 3
|
||||
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) // NOLINT
|
||||
|
||||
class JitdumpCodeObserver : public CodeObserver {
|
||||
public:
|
||||
JitdumpCodeObserver() {
|
||||
ASSERT(FLAG_generate_perf_jitdump);
|
||||
out_file_ = NULL;
|
||||
clock_fd_ = -1;
|
||||
clock_id_ = kInvalidClockId;
|
||||
code_sequence_ = 0;
|
||||
Dart_FileOpenCallback file_open = Isolate::file_open_callback();
|
||||
Dart_FileWriteCallback file_write = Isolate::file_write_callback();
|
||||
Dart_FileCloseCallback file_close = Isolate::file_close_callback();
|
||||
if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
|
||||
return;
|
||||
}
|
||||
// The Jitdump code observer writes all jitted code into the file
|
||||
// 'perf.jitdump' in the current working directory. We open the file once
|
||||
// on initialization and close it when the VM is going down.
|
||||
{
|
||||
// Open the file.
|
||||
const char* filename = "perf.jitdump";
|
||||
out_file_ = (*file_open)(filename, true);
|
||||
ASSERT(out_file_ != NULL);
|
||||
// Write the jit dump header.
|
||||
WriteHeader();
|
||||
}
|
||||
// perf uses an internal clock and because our output is merged with data
|
||||
// collected by perf our timestamps must be consistent. Using
|
||||
// the posix-clock-module (/dev/trace_clock) as our time source ensures
|
||||
// we are consistent with the perf timestamps.
|
||||
clock_id_ = kInvalidClockId;
|
||||
clock_fd_ = open("/dev/trace_clock", O_RDONLY);
|
||||
if (clock_fd_ >= 0) {
|
||||
clock_id_ = FD_TO_CLOCKID(clock_fd_);
|
||||
}
|
||||
}
|
||||
|
||||
~JitdumpCodeObserver() {
|
||||
Dart_FileCloseCallback file_close = Isolate::file_close_callback();
|
||||
if (file_close == NULL) {
|
||||
return;
|
||||
}
|
||||
ASSERT(out_file_ != NULL);
|
||||
(*file_close)(out_file_);
|
||||
if (clock_fd_ >= 0) {
|
||||
close(clock_fd_);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool IsActive() const {
|
||||
return FLAG_generate_perf_jitdump && (out_file_ != NULL);
|
||||
}
|
||||
|
||||
virtual void Notify(const char* name,
|
||||
uword base,
|
||||
uword prologue_offset,
|
||||
uword size,
|
||||
bool optimized) {
|
||||
WriteCodeLoad(name, base, prologue_offset, size, optimized);
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint32_t kJitHeaderMagic = 0x4A695444;
|
||||
static const uint32_t kJitHeaderMagicSw = 0x4454694A;
|
||||
static const uint32_t kJitHeaderVersion = 0x1;
|
||||
static const uint32_t kElfMachIA32 = 3;
|
||||
static const uint32_t kElfMachX64 = 62;
|
||||
static const uint32_t kElfMachARM = 40;
|
||||
// TODO(zra): Find the right ARM64 constant.
|
||||
static const uint32_t kElfMachARM64 = 40;
|
||||
static const uint32_t kElfMachMIPS = 10;
|
||||
static const int kInvalidClockId = -1;
|
||||
|
||||
struct jitheader {
|
||||
uint32_t magic; /* characters "jItD" */
|
||||
uint32_t version; /* header version */
|
||||
uint32_t total_size; /* total size of header */
|
||||
uint32_t elf_mach; /* elf mach target */
|
||||
uint32_t pad1; /* reserved */
|
||||
uint32_t pid; /* JIT process id */
|
||||
uint64_t timestamp; /* timestamp */
|
||||
};
|
||||
|
||||
/* record prefix (mandatory in each record) */
|
||||
struct jr_prefix {
|
||||
uint32_t id;
|
||||
uint32_t total_size;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
enum jit_record_type {
|
||||
JIT_CODE_LOAD = 0,
|
||||
/* JIT_CODE_MOVE = 1, */
|
||||
/* JIT_CODE_DEBUG_INFO = 2, */
|
||||
/* JIT_CODE_CLOSE = 3, */
|
||||
JIT_CODE_MAX = 4,
|
||||
};
|
||||
|
||||
struct jr_code_load {
|
||||
struct jr_prefix prefix;
|
||||
uint32_t pid;
|
||||
uint32_t tid;
|
||||
uint64_t vma;
|
||||
uint64_t code_addr;
|
||||
uint64_t code_size;
|
||||
uint64_t code_index;
|
||||
};
|
||||
|
||||
const char* GenerateCodeName(const char* name, bool optimized) {
|
||||
const char* marker = optimized ? "*" : "";
|
||||
return OS::SCreate(Thread::Current()->zone(), "%s%s", marker, name);
|
||||
}
|
||||
|
||||
uint32_t GetElfMach() {
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
return kElfMachIA32;
|
||||
#elif defined(TARGET_ARCH_X64)
|
||||
return kElfMachX64;
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
return kElfMachARM;
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
return kElfMachARM64;
|
||||
#elif defined(TARGET_ARCH_MIPS)
|
||||
return kElfMachMIPS;
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
}
|
||||
|
||||
pid_t gettid() {
|
||||
// libc doesn't wrap the Linux-specific gettid system call.
|
||||
// Note that this thread id is not the same as the posix thread id.
|
||||
return syscall(SYS_gettid);
|
||||
}
|
||||
|
||||
uint64_t GetKernelTimeNanos() {
|
||||
if (clock_id_ != kInvalidClockId) {
|
||||
struct timespec ts;
|
||||
int r = clock_gettime(clock_id_, &ts);
|
||||
ASSERT(r == 0);
|
||||
uint64_t nanos = static_cast<uint64_t>(ts.tv_sec) *
|
||||
static_cast<uint64_t>(kNanosecondsPerSecond);
|
||||
nanos += static_cast<uint64_t>(ts.tv_nsec);
|
||||
return nanos;
|
||||
} else {
|
||||
return OS::GetCurrentTimeMicros() * kNanosecondsPerMicrosecond;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteHeader() {
|
||||
Dart_FileWriteCallback file_write = Isolate::file_write_callback();
|
||||
ASSERT(file_write != NULL);
|
||||
ASSERT(out_file_ != NULL);
|
||||
jitheader header;
|
||||
header.magic = kJitHeaderMagic;
|
||||
header.version = kJitHeaderVersion;
|
||||
header.total_size = sizeof(jitheader);
|
||||
header.pad1 = 0x0;
|
||||
header.elf_mach = GetElfMach();
|
||||
header.pid = getpid();
|
||||
header.timestamp = GetKernelTimeNanos();
|
||||
{
|
||||
MutexLocker ml(CodeObservers::mutex());
|
||||
(*file_write)(&header, sizeof(header), out_file_);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteCodeLoad(const char* name, uword base, uword prologue_offset,
|
||||
uword code_size, bool optimized) {
|
||||
Dart_FileWriteCallback file_write = Isolate::file_write_callback();
|
||||
ASSERT(file_write != NULL);
|
||||
ASSERT(out_file_ != NULL);
|
||||
|
||||
const char* code_name = GenerateCodeName(name, optimized);
|
||||
const intptr_t code_name_size = strlen(code_name) + 1;
|
||||
uint8_t* code_pointer = reinterpret_cast<uint8_t*>(base);
|
||||
|
||||
jr_code_load code_load;
|
||||
code_load.prefix.id = JIT_CODE_LOAD;
|
||||
code_load.prefix.total_size =
|
||||
sizeof(code_load) + code_name_size + code_size;
|
||||
code_load.prefix.timestamp = GetKernelTimeNanos();
|
||||
code_load.pid = getpid();
|
||||
code_load.tid = gettid();
|
||||
code_load.vma = 0x0; // Our addresses are absolute.
|
||||
code_load.code_addr = base;
|
||||
code_load.code_size = code_size;
|
||||
|
||||
{
|
||||
MutexLocker ml(CodeObservers::mutex());
|
||||
// Set this field under the index.
|
||||
code_load.code_index = code_sequence_++;
|
||||
// Write structures.
|
||||
(*file_write)(&code_load, sizeof(code_load), out_file_);
|
||||
(*file_write)(code_name, code_name_size, out_file_);
|
||||
(*file_write)(code_pointer, code_size, out_file_);
|
||||
}
|
||||
}
|
||||
|
||||
void* out_file_;
|
||||
int clock_fd_;
|
||||
int clock_id_;
|
||||
uint64_t code_sequence_;
|
||||
DISALLOW_COPY_AND_ASSIGN(JitdumpCodeObserver);
|
||||
};
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
const char* OS::Name() {
|
||||
return "linux";
|
||||
@@ -617,18 +370,11 @@ bool OS::StringToInt64(const char* str, int64_t* value) {
|
||||
|
||||
|
||||
void OS::RegisterCodeObservers() {
|
||||
#ifndef PRODUCT
|
||||
if (FLAG_generate_perf_events_symbols) {
|
||||
CodeObservers::Register(new PerfCodeObserver);
|
||||
}
|
||||
if (FLAG_generate_gdb_symbols) {
|
||||
CodeObservers::Register(new GdbCodeObserver);
|
||||
}
|
||||
if (FLAG_generate_perf_jitdump) {
|
||||
CodeObservers::Register(new JitdumpCodeObserver);
|
||||
}
|
||||
#if defined(DART_VTUNE_SUPPORT)
|
||||
CodeObservers::Register(new VTuneCodeObserver);
|
||||
#endif
|
||||
#endif // !PRODUCT
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/regexp_assembler.h"
|
||||
#include "vm/report.h"
|
||||
#include "vm/resolver.h"
|
||||
#include "vm/safepoint.h"
|
||||
#include "vm/scanner.h"
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
class JSONObject;
|
||||
|
||||
// Timer class allows timing of specific operations in the VM.
|
||||
class Timer : public ValueObject {
|
||||
public:
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
// Copyright (c) 2013, 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 "vm/isolate.h"
|
||||
#include "vm/json_stream.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/trace_buffer.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
TraceBuffer::TraceBuffer(Isolate* isolate, intptr_t capacity)
|
||||
: isolate_(isolate), ring_capacity_(capacity) {
|
||||
ring_cursor_ = 0;
|
||||
ring_ = reinterpret_cast<TraceBufferEntry*>(
|
||||
calloc(ring_capacity_, sizeof(TraceBufferEntry))); // NOLINT
|
||||
}
|
||||
|
||||
|
||||
TraceBuffer::~TraceBuffer() {
|
||||
ASSERT(ring_ != NULL);
|
||||
Clear();
|
||||
free(ring_);
|
||||
if (isolate_ != NULL) {
|
||||
isolate_->set_trace_buffer(NULL);
|
||||
isolate_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::Init(Isolate* isolate, intptr_t capacity) {
|
||||
TraceBuffer* trace_buffer = new TraceBuffer(isolate, capacity);
|
||||
isolate->set_trace_buffer(trace_buffer);
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::Clear() {
|
||||
for (intptr_t i = 0; i < ring_capacity_; i++) {
|
||||
TraceBufferEntry& entry = ring_[i];
|
||||
entry.micros = 0;
|
||||
free(entry.message);
|
||||
entry.message = NULL;
|
||||
entry.message_is_escaped = false;
|
||||
}
|
||||
ring_cursor_ = 0;
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::Fill(TraceBufferEntry* entry, int64_t micros,
|
||||
char* msg, bool msg_is_escaped) {
|
||||
if (entry->message != NULL) {
|
||||
// Recycle TraceBufferEntry.
|
||||
free(entry->message);
|
||||
}
|
||||
entry->message = msg;
|
||||
entry->message_is_escaped = msg_is_escaped;
|
||||
entry->micros = micros;
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::AppendTrace(int64_t micros, char* msg, bool msg_is_escaped) {
|
||||
const intptr_t index = ring_cursor_;
|
||||
TraceBufferEntry* trace_entry = &ring_[index];
|
||||
Fill(trace_entry, micros, msg, msg_is_escaped);
|
||||
ring_cursor_ = RingIndex(ring_cursor_ + 1);
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::Trace(int64_t micros, const char* msg, bool msg_is_escaped) {
|
||||
ASSERT(msg != NULL);
|
||||
char* message_copy = strdup(msg);
|
||||
AppendTrace(micros, message_copy, msg_is_escaped);
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::Trace(const char* msg, bool msg_is_escaped) {
|
||||
Trace(OS::GetCurrentTimeMicros(), msg, msg_is_escaped);
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::TraceF(const char* format, ...) {
|
||||
const int64_t micros = OS::GetCurrentTimeMicros();
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const intptr_t len = OS::VSNPrint(NULL, 0, format, args);
|
||||
va_end(args);
|
||||
char* p = reinterpret_cast<char*>(malloc(len+1));
|
||||
va_start(args, format);
|
||||
const intptr_t len2 = OS::VSNPrint(p, len+1, format, args);
|
||||
va_end(args);
|
||||
ASSERT(len == len2);
|
||||
AppendTrace(micros, p);
|
||||
}
|
||||
|
||||
|
||||
void TraceBuffer::PrintToJSONStream(JSONStream* stream) const {
|
||||
JSONObject json_trace_buffer(stream);
|
||||
json_trace_buffer.AddProperty("type", "TraceBuffer");
|
||||
// TODO(johnmccutchan): Send cursor position in response.
|
||||
JSONArray json_trace_buffer_array(&json_trace_buffer, "members");
|
||||
// Scan forward until we find the first entry which isn't empty.
|
||||
// TODO(johnmccutchan): Accept cursor start position as input.
|
||||
intptr_t start = -1;
|
||||
for (intptr_t i = 0; i < ring_capacity_; i++) {
|
||||
intptr_t index = RingIndex(i + ring_cursor_);
|
||||
if (!ring_[index].empty()) {
|
||||
start = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// No messages in trace buffer.
|
||||
if (start == -1) {
|
||||
return;
|
||||
}
|
||||
for (intptr_t i = 0; i < ring_capacity_; i++) {
|
||||
intptr_t index = RingIndex(start + i);
|
||||
const TraceBufferEntry& entry = ring_[index];
|
||||
if (entry.empty()) {
|
||||
// Empty entry, stop.
|
||||
break;
|
||||
}
|
||||
JSONObject trace_entry(&json_trace_buffer_array);
|
||||
trace_entry.AddProperty("type", "TraceBufferEntry");
|
||||
double seconds = static_cast<double>(entry.micros) /
|
||||
static_cast<double>(kMicrosecondsPerSecond);
|
||||
trace_entry.AddProperty("time", seconds);
|
||||
if (entry.message_is_escaped) {
|
||||
trace_entry.AddPropertyNoEscape("message", entry.message);
|
||||
} else {
|
||||
trace_entry.AddProperty("message", entry.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
@@ -1,70 +0,0 @@
|
||||
// Copyright (c) 2013, 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 VM_TRACE_BUFFER_H_
|
||||
#define VM_TRACE_BUFFER_H_
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
#include "vm/json_stream.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class JSONStream;
|
||||
class Script;
|
||||
|
||||
struct TraceBufferEntry {
|
||||
int64_t micros;
|
||||
char* message;
|
||||
bool message_is_escaped;
|
||||
bool empty() const {
|
||||
return message == NULL;
|
||||
}
|
||||
};
|
||||
|
||||
class TraceBuffer {
|
||||
public:
|
||||
static const intptr_t kDefaultCapacity = 1024;
|
||||
|
||||
static void Init(Isolate* isolate, intptr_t capacity = kDefaultCapacity);
|
||||
|
||||
~TraceBuffer();
|
||||
|
||||
void Clear();
|
||||
|
||||
// Internally message is copied.
|
||||
void Trace(int64_t micros, const char* msg, bool msg_is_escaped = false);
|
||||
// Internally message is copied.
|
||||
void Trace(const char* msg, bool msg_is_escaped = false);
|
||||
void TraceF(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
|
||||
|
||||
void PrintToJSONStream(JSONStream* stream) const;
|
||||
|
||||
// Accessors for testing.
|
||||
TraceBufferEntry* At(intptr_t i) const { return &ring_[RingIndex(i)]; }
|
||||
intptr_t Length() const { return ring_cursor_; }
|
||||
|
||||
private:
|
||||
TraceBuffer(Isolate* isolate, intptr_t capacity);
|
||||
void Cleanup();
|
||||
void Fill(TraceBufferEntry* entry, int64_t micros,
|
||||
char* msg, bool msg_is_escaped = false);
|
||||
void AppendTrace(int64_t micros, char* msg, bool msg_is_escaped = false);
|
||||
|
||||
Isolate* isolate_;
|
||||
TraceBufferEntry* ring_;
|
||||
const intptr_t ring_capacity_;
|
||||
intptr_t ring_cursor_;
|
||||
|
||||
intptr_t RingIndex(intptr_t i) const {
|
||||
return i % ring_capacity_;
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TraceBuffer);
|
||||
};
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_TRACE_BUFFER_H_
|
||||
@@ -1,110 +0,0 @@
|
||||
// Copyright (c) 2013, 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 "platform/assert.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/json_stream.h"
|
||||
#include "vm/trace_buffer.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
TEST_CASE(TraceBufferEmpty) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
TraceBuffer::Init(isolate, 3);
|
||||
TraceBuffer* trace_buffer = isolate->trace_buffer();
|
||||
{
|
||||
JSONStream js;
|
||||
trace_buffer->PrintToJSONStream(&js);
|
||||
EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":[]}", js.ToCString());
|
||||
}
|
||||
delete trace_buffer;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE(TraceBufferClear) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
TraceBuffer::Init(isolate, 3);
|
||||
TraceBuffer* trace_buffer = isolate->trace_buffer();
|
||||
trace_buffer->Trace(kMicrosecondsPerSecond * 1, "abc");
|
||||
trace_buffer->Clear();
|
||||
{
|
||||
JSONStream js;
|
||||
trace_buffer->PrintToJSONStream(&js);
|
||||
EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":[]}", js.ToCString());
|
||||
}
|
||||
delete trace_buffer;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE(TraceBufferTrace) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
TraceBuffer::Init(isolate, 3);
|
||||
TraceBuffer* trace_buffer = isolate->trace_buffer();
|
||||
|
||||
trace_buffer->Trace(kMicrosecondsPerSecond * 1, "abc");
|
||||
{
|
||||
JSONStream js;
|
||||
trace_buffer->PrintToJSONStream(&js);
|
||||
EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":1.000000,"
|
||||
"\"message\":\"abc\"}]}", js.ToCString());
|
||||
}
|
||||
trace_buffer->Trace(kMicrosecondsPerSecond * 2, "def");
|
||||
{
|
||||
JSONStream js;
|
||||
trace_buffer->PrintToJSONStream(&js);
|
||||
EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":1.000000,"
|
||||
"\"message\":\"abc\"},"
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":2.000000,"
|
||||
"\"message\":\"def\"}]}", js.ToCString());
|
||||
}
|
||||
trace_buffer->Trace(kMicrosecondsPerSecond * 3, "ghi");
|
||||
{
|
||||
JSONStream js;
|
||||
trace_buffer->PrintToJSONStream(&js);
|
||||
EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":1.000000,"
|
||||
"\"message\":\"abc\"},"
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":2.000000,"
|
||||
"\"message\":\"def\"},"
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":3.000000,"
|
||||
"\"message\":\"ghi\"}]}", js.ToCString());
|
||||
}
|
||||
// This will overwrite the first Trace.
|
||||
trace_buffer->Trace(kMicrosecondsPerSecond * 4, "jkl");
|
||||
{
|
||||
JSONStream js;
|
||||
trace_buffer->PrintToJSONStream(&js);
|
||||
EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":2.000000,"
|
||||
"\"message\":\"def\"},"
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":3.000000,"
|
||||
"\"message\":\"ghi\"},"
|
||||
"{\"type\":\"TraceBufferEntry\",\"time\":4.000000,"
|
||||
"\"message\":\"jkl\"}]}", js.ToCString());
|
||||
}
|
||||
delete trace_buffer;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE(TraceBufferTraceF) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
TraceBuffer::Init(isolate, 3);
|
||||
TraceBuffer* trace_buffer = isolate->trace_buffer();
|
||||
trace_buffer->TraceF("foo %d %s", 99, "bar");
|
||||
{
|
||||
JSONStream js;
|
||||
trace_buffer->PrintToJSONStream(&js);
|
||||
EXPECT_SUBSTRING("foo 99 bar", js.ToCString());
|
||||
}
|
||||
delete trace_buffer;
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
} // namespace dart
|
||||
@@ -144,9 +144,6 @@
|
||||
'debugger_ia32.cc',
|
||||
'debugger_mips.cc',
|
||||
'debugger_x64.cc',
|
||||
'debuginfo.h',
|
||||
'debuginfo_android.cc',
|
||||
'debuginfo_linux.cc',
|
||||
'deferred_objects.cc',
|
||||
'deferred_objects.h',
|
||||
'deopt_instructions.cc',
|
||||
@@ -162,7 +159,6 @@
|
||||
'double_conversion.cc',
|
||||
'double_conversion.h',
|
||||
'double_internals.h',
|
||||
'elfgen.h',
|
||||
'exceptions.cc',
|
||||
'exceptions.h',
|
||||
'exceptions_test.cc',
|
||||
@@ -201,10 +197,6 @@
|
||||
'gc_marker.h',
|
||||
'gc_sweeper.cc',
|
||||
'gc_sweeper.h',
|
||||
'gdbjit_android.cc',
|
||||
'gdbjit_android.h',
|
||||
'gdbjit_linux.cc',
|
||||
'gdbjit_linux.h',
|
||||
'globals.h',
|
||||
'growable_array.h',
|
||||
'growable_array_test.cc',
|
||||
@@ -482,9 +474,6 @@
|
||||
'token.h',
|
||||
'token_position.cc',
|
||||
'token_position.h',
|
||||
'trace_buffer.cc',
|
||||
'trace_buffer.h',
|
||||
'trace_buffer_test.cc',
|
||||
'unibrow.cc',
|
||||
'unibrow.h',
|
||||
'unibrow-inl.h',
|
||||
@@ -508,8 +497,6 @@
|
||||
'virtual_memory_test.cc',
|
||||
'virtual_memory_win.cc',
|
||||
'visitor.h',
|
||||
'vtune.cc',
|
||||
'vtune.h',
|
||||
'weak_code.cc',
|
||||
'weak_code.h',
|
||||
'weak_table.cc',
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// 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 "vm/vtune.h"
|
||||
|
||||
#include <jitprofiling.h>
|
||||
|
||||
#include "platform/assert.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
bool VTuneCodeObserver::IsActive() const {
|
||||
return (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON);
|
||||
}
|
||||
|
||||
|
||||
void VTuneCodeObserver::Notify(const char* name,
|
||||
uword base,
|
||||
uword prologue_offset,
|
||||
uword size,
|
||||
bool optimized) {
|
||||
ASSERT(IsActive());
|
||||
iJIT_Method_Load jmethod;
|
||||
memset(&jmethod, 0, sizeof(jmethod));
|
||||
jmethod.method_id = iJIT_GetNewMethodID();
|
||||
jmethod.method_name = const_cast<char*>(name);
|
||||
jmethod.method_load_address = reinterpret_cast<void*>(base);
|
||||
jmethod.method_size = size;
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &jmethod);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
@@ -1,28 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef VM_VTUNE_H_
|
||||
#define VM_VTUNE_H_
|
||||
|
||||
#include "vm/code_observers.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if defined(DART_VTUNE_SUPPORT)
|
||||
class VTuneCodeObserver : public CodeObserver {
|
||||
public:
|
||||
virtual bool IsActive() const;
|
||||
|
||||
virtual void Notify(const char* name,
|
||||
uword base,
|
||||
uword prologue_offset,
|
||||
uword size,
|
||||
bool optimized);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_VTUNE_H_
|
||||
Reference in New Issue
Block a user