mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:49:47 +00:00
Adds external CodeObserver callback to the VM.
This enables external (such as by the embedder) accounting of the code objects for resolving stack traces. Bug: b/117752777 Change-Id: I824fb9b27e9aa97373b155cf07e9e8f17722ba07 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/85360 Commit-Queue: Clement Skau <cskau@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
f03ddc496b
commit
5b113ee193
|
@ -322,7 +322,7 @@ static int Main(int argc, const char** argv) {
|
|||
dart::bin::DartUtils::OpenFile, dart::bin::DartUtils::ReadFile,
|
||||
dart::bin::DartUtils::WriteFile, dart::bin::DartUtils::CloseFile,
|
||||
nullptr /* entropy_source */, nullptr /* get_service_assets */,
|
||||
start_kernel_isolate);
|
||||
start_kernel_isolate, nullptr /* observer */);
|
||||
if (error != nullptr) {
|
||||
Syslog::PrintErr("Failed to initialize VM: %s\n", error);
|
||||
free(error);
|
||||
|
|
|
@ -714,7 +714,31 @@ typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)();
|
|||
* The current version of the Dart_InitializeFlags. Should be incremented every
|
||||
* time Dart_InitializeFlags changes in a binary incompatible way.
|
||||
*/
|
||||
#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000003)
|
||||
#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000004)
|
||||
|
||||
/** Forward declaration */
|
||||
struct Dart_CodeObserver;
|
||||
|
||||
/**
|
||||
* Callback provided by the embedder that is used by the VM to notify on code
|
||||
* object creation, *before* it is invoked the first time.
|
||||
* This is useful for embedders wanting to e.g. keep track of PCs beyond
|
||||
* the lifetime of the garbage collected code objects.
|
||||
* Note that an address range may be used by more than one code object over the
|
||||
* lifecycle of a process. Clients of this function should record timestamps for
|
||||
* these compilation events and when collecting PCs to disambiguate reused
|
||||
* address ranges.
|
||||
*/
|
||||
typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer,
|
||||
const char* name,
|
||||
uintptr_t base,
|
||||
uintptr_t size);
|
||||
|
||||
typedef struct Dart_CodeObserver {
|
||||
void* data;
|
||||
|
||||
Dart_OnNewCodeCallback on_new_code;
|
||||
} Dart_CodeObserver;
|
||||
|
||||
/**
|
||||
* Describes how to initialize the VM. Used with Dart_Initialize.
|
||||
|
@ -736,6 +760,8 @@ typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)();
|
|||
* \param get_service_assets A function to be called by the service isolate when
|
||||
* it requires the vmservice assets archive.
|
||||
* See Dart_GetVMServiceAssetsArchive.
|
||||
* \param code_observer An external code observer callback function.
|
||||
* The observer can be invoked as early as during the Dart_Initialize() call.
|
||||
*/
|
||||
typedef struct {
|
||||
int32_t version;
|
||||
|
@ -752,6 +778,7 @@ typedef struct {
|
|||
Dart_EntropySource entropy_source;
|
||||
Dart_GetVMServiceAssetsArchive get_service_assets;
|
||||
bool start_kernel_isolate;
|
||||
Dart_CodeObserver* code_observer;
|
||||
} Dart_InitializeParams;
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "platform/assert.h"
|
||||
#include "vm/bootstrap.h"
|
||||
#include "vm/class_id.h"
|
||||
#include "vm/code_observers.h"
|
||||
#include "vm/compiler/backend/code_statistics.h"
|
||||
#include "vm/compiler/relocation.h"
|
||||
#include "vm/dart.h"
|
||||
|
@ -1572,6 +1573,19 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
|||
code->ptr()->state_bits_ = d->Read<int32_t>();
|
||||
}
|
||||
}
|
||||
|
||||
#if !(defined(DART_PRECOMPILED_RUNTIME) || defined(PRODUCT))
|
||||
void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
|
||||
if (!CodeObservers::AreActive()) return;
|
||||
Code& code = Code::Handle(zone);
|
||||
Function& function = Function::Handle(zone);
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
code ^= refs.At(id);
|
||||
function = code.function();
|
||||
Code::NotifyCodeObservers(function, code, code.is_optimized());
|
||||
}
|
||||
}
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
};
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
|
|
@ -15,6 +15,30 @@ Mutex* CodeObservers::mutex_ = NULL;
|
|||
intptr_t CodeObservers::observers_length_ = 0;
|
||||
CodeObserver** CodeObservers::observers_ = NULL;
|
||||
|
||||
class ExternalCodeObserverAdapter : public CodeObserver {
|
||||
public:
|
||||
explicit ExternalCodeObserverAdapter(Dart_CodeObserver* delegate)
|
||||
: delegate_(delegate) {}
|
||||
|
||||
virtual bool IsActive() const { return true; }
|
||||
|
||||
virtual void Notify(const char* name,
|
||||
uword base,
|
||||
uword prologue_offset,
|
||||
uword size,
|
||||
bool optimized,
|
||||
const CodeComments* comments) {
|
||||
return delegate_->on_new_code(delegate_, name, base, size);
|
||||
}
|
||||
|
||||
private:
|
||||
Dart_CodeObserver* delegate_;
|
||||
};
|
||||
|
||||
void CodeObservers::RegisterExternal(Dart_CodeObserver* observer) {
|
||||
if (observer != nullptr) Register(new ExternalCodeObserverAdapter(observer));
|
||||
}
|
||||
|
||||
void CodeObservers::Register(CodeObserver* observer) {
|
||||
observers_length_++;
|
||||
observers_ = reinterpret_cast<CodeObserver**>(
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "vm/allocation.h"
|
||||
#include "vm/globals.h"
|
||||
|
||||
#include "include/dart_api.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -55,6 +57,8 @@ class CodeObservers : public AllStatic {
|
|||
public:
|
||||
static void Init();
|
||||
|
||||
static void RegisterExternal(Dart_CodeObserver* observer);
|
||||
|
||||
static void Register(CodeObserver* observer);
|
||||
|
||||
// Notify all active code observers about a newly created code object.
|
||||
|
|
|
@ -140,7 +140,8 @@ char* Dart::Init(const uint8_t* vm_isolate_snapshot,
|
|||
Dart_FileCloseCallback file_close,
|
||||
Dart_EntropySource entropy_source,
|
||||
Dart_GetVMServiceAssetsArchive get_service_assets,
|
||||
bool start_kernel_isolate) {
|
||||
bool start_kernel_isolate,
|
||||
Dart_CodeObserver* observer) {
|
||||
CheckOffsets();
|
||||
// TODO(iposva): Fix race condition here.
|
||||
if (vm_isolate_ != NULL || !Flags::Initialized()) {
|
||||
|
@ -194,6 +195,7 @@ char* Dart::Init(const uint8_t* vm_isolate_snapshot,
|
|||
set_entropy_source_callback(entropy_source);
|
||||
OS::Init();
|
||||
NOT_IN_PRODUCT(CodeObservers::Init());
|
||||
NOT_IN_PRODUCT(CodeObservers::RegisterExternal(observer));
|
||||
start_time_micros_ = OS::GetCurrentMonotonicMicros();
|
||||
VirtualMemory::Init();
|
||||
OSThread::Init();
|
||||
|
|
|
@ -38,7 +38,8 @@ class Dart : public AllStatic {
|
|||
Dart_FileCloseCallback file_close,
|
||||
Dart_EntropySource entropy_source,
|
||||
Dart_GetVMServiceAssetsArchive get_service_assets,
|
||||
bool start_kernel_isolate);
|
||||
bool start_kernel_isolate,
|
||||
Dart_CodeObserver* observer);
|
||||
|
||||
// Returns null if cleanup succeeds, otherwise returns an error message
|
||||
// (caller owns error message and has to free it).
|
||||
|
|
|
@ -1009,7 +1009,7 @@ DART_EXPORT char* Dart_Initialize(Dart_InitializeParams* params) {
|
|||
params->thread_exit, params->file_open, params->file_read,
|
||||
params->file_write, params->file_close,
|
||||
params->entropy_source, params->get_service_assets,
|
||||
params->start_kernel_isolate);
|
||||
params->start_kernel_isolate, params->code_observer);
|
||||
}
|
||||
|
||||
DART_EXPORT char* Dart_Cleanup() {
|
||||
|
|
|
@ -57,6 +57,32 @@ UNIT_TEST_CASE(DartAPI_DartInitializeAfterCleanup) {
|
|||
EXPECT(Dart_Cleanup() == NULL);
|
||||
}
|
||||
|
||||
UNIT_TEST_CASE(DartAPI_DartInitializeCallsCodeObserver) {
|
||||
EXPECT(Dart_SetVMFlags(TesterState::argc, TesterState::argv) == NULL);
|
||||
Dart_InitializeParams params;
|
||||
memset(¶ms, 0, sizeof(Dart_InitializeParams));
|
||||
params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
|
||||
params.vm_snapshot_data = TesterState::vm_snapshot_data;
|
||||
params.create = TesterState::create_callback;
|
||||
params.shutdown = TesterState::shutdown_callback;
|
||||
params.cleanup = TesterState::cleanup_callback;
|
||||
params.start_kernel_isolate = true;
|
||||
|
||||
bool was_called = false;
|
||||
Dart_CodeObserver code_observer;
|
||||
code_observer.data = &was_called;
|
||||
code_observer.on_new_code = [](Dart_CodeObserver* observer, const char* name,
|
||||
uintptr_t base, uintptr_t size) {
|
||||
*static_cast<bool*>(observer->data) = true;
|
||||
};
|
||||
params.code_observer = &code_observer;
|
||||
|
||||
// Reinitialize and ensure we can execute Dart code.
|
||||
EXPECT(Dart_Initialize(¶ms) == NULL);
|
||||
EXPECT(was_called);
|
||||
EXPECT(Dart_Cleanup() == NULL);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_ErrorHandleBasics) {
|
||||
const char* kScriptChars =
|
||||
"void testMain() {\n"
|
||||
|
|
Loading…
Reference in a new issue