blob: 1023043f73de0df196e7bd6ad5d64c88f9d25654 [file] [log] [blame]
// Copyright (c) 2015, 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/service_event.h"
#include "vm/message_handler.h"
namespace dart {
// Translate from the legacy DebugEvent to a ServiceEvent.
static ServiceEvent::EventKind TranslateEventKind(
DebuggerEvent::EventType kind) {
switch (kind) {
case DebuggerEvent::kIsolateCreated:
return ServiceEvent::kIsolateStart;
case DebuggerEvent::kIsolateShutdown:
return ServiceEvent::kIsolateExit;
case DebuggerEvent::kBreakpointReached:
return ServiceEvent::kPauseBreakpoint;
case DebuggerEvent::kIsolateInterrupted:
return ServiceEvent::kPauseInterrupted;
case DebuggerEvent::kExceptionThrown:
return ServiceEvent::kPauseException;
default:
UNREACHABLE();
return ServiceEvent::kIllegal;
}
}
ServiceEvent::ServiceEvent(Isolate* isolate, EventKind event_kind)
: isolate_(isolate),
kind_(event_kind),
embedder_kind_(NULL),
embedder_stream_id_(NULL),
breakpoint_(NULL),
top_frame_(NULL),
exception_(NULL),
async_continuation_(NULL),
at_async_jump_(false),
inspectee_(NULL),
gc_stats_(NULL),
bytes_(NULL),
bytes_length_(0),
timestamp_(OS::GetCurrentTimeMillis()) {
if ((event_kind == ServiceEvent::kPauseStart) ||
(event_kind == ServiceEvent::kPauseExit)) {
timestamp_ = isolate->message_handler()->paused_timestamp();
} else if (event_kind == ServiceEvent::kResume) {
timestamp_ = isolate->last_resume_timestamp();
}
}
ServiceEvent::ServiceEvent(const DebuggerEvent* debugger_event)
: isolate_(debugger_event->isolate()),
kind_(TranslateEventKind(debugger_event->type())),
breakpoint_(NULL),
top_frame_(NULL),
exception_(NULL),
async_continuation_(NULL),
inspectee_(NULL),
gc_stats_(NULL),
bytes_(NULL),
bytes_length_(0),
timestamp_(OS::GetCurrentTimeMillis()) {
DebuggerEvent::EventType type = debugger_event->type();
if (type == DebuggerEvent::kBreakpointReached) {
set_breakpoint(debugger_event->breakpoint());
set_async_continuation(debugger_event->async_continuation());
set_at_async_jump(debugger_event->at_async_jump());
}
if (type == DebuggerEvent::kExceptionThrown) {
set_exception(debugger_event->exception());
}
if (type == DebuggerEvent::kBreakpointReached ||
type == DebuggerEvent::kIsolateInterrupted ||
type == DebuggerEvent::kExceptionThrown) {
set_top_frame(debugger_event->top_frame());
}
if (debugger_event->timestamp() != -1) {
timestamp_ = debugger_event->timestamp();
}
}
const char* ServiceEvent::KindAsCString() const {
switch (kind()) {
case kVMUpdate:
return "VMUpdate";
case kIsolateStart:
return "IsolateStart";
case kIsolateRunnable:
return "IsolateRunnable";
case kIsolateExit:
return "IsolateExit";
case kIsolateUpdate:
return "IsolateUpdate";
case kPauseStart:
return "PauseStart";
case kPauseExit:
return "PauseExit";
case kPauseBreakpoint:
return "PauseBreakpoint";
case kPauseInterrupted:
return "PauseInterrupted";
case kPauseException:
return "PauseException";
case kResume:
return "Resume";
case kBreakpointAdded:
return "BreakpointAdded";
case kBreakpointResolved:
return "BreakpointResolved";
case kBreakpointRemoved:
return "BreakpointRemoved";
case kGC:
return "GC"; // TODO(koda): Change to GarbageCollected.
case kInspect:
return "Inspect";
case kEmbedder:
return embedder_kind();
case kLogging:
return "_Logging";
case kDebuggerSettingsUpdate:
return "_DebuggerSettingsUpdate";
case kIllegal:
return "Illegal";
default:
UNREACHABLE();
return "Unknown";
}
}
const char* ServiceEvent::stream_id() const {
switch (kind()) {
case kVMUpdate:
return Service::vm_stream.id();
case kIsolateStart:
case kIsolateRunnable:
case kIsolateExit:
case kIsolateUpdate:
return Service::isolate_stream.id();
case kPauseStart:
case kPauseExit:
case kPauseBreakpoint:
case kPauseInterrupted:
case kPauseException:
case kResume:
case kBreakpointAdded:
case kBreakpointResolved:
case kBreakpointRemoved:
case kInspect:
case kDebuggerSettingsUpdate:
return Service::debug_stream.id();
case kGC:
return Service::gc_stream.id();
case kEmbedder:
return embedder_stream_id_;
case kLogging:
return Service::logging_stream.id();
default:
UNREACHABLE();
return NULL;
}
}
void ServiceEvent::PrintJSON(JSONStream* js) const {
JSONObject jsobj(js);
PrintJSONHeader(&jsobj);
if (kind() == kPauseBreakpoint) {
JSONArray jsarr(&jsobj, "pauseBreakpoints");
// TODO(rmacnak): If we are paused at more than one breakpoint,
// provide it here.
if (breakpoint() != NULL) {
jsarr.AddValue(breakpoint());
}
} else {
if (breakpoint() != NULL) {
jsobj.AddProperty("breakpoint", breakpoint());
}
}
if (kind() == kDebuggerSettingsUpdate) {
JSONObject jssettings(&jsobj, "_debuggerSettings");
isolate()->debugger()->PrintSettingsToJSONObject(&jssettings);
}
if (top_frame() != NULL) {
JSONObject jsFrame(&jsobj, "topFrame");
top_frame()->PrintToJSONObject(&jsFrame);
intptr_t index = 0; // Avoid ambiguity in call to AddProperty.
jsFrame.AddProperty("index", index);
}
if (exception() != NULL) {
jsobj.AddProperty("exception", *(exception()));
}
if (async_continuation() != NULL && !async_continuation()->IsNull()) {
jsobj.AddProperty("_asyncContinuation", *(async_continuation()));
jsobj.AddProperty("_atAsyncJump", at_async_jump());
}
if (inspectee() != NULL) {
jsobj.AddProperty("inspectee", *(inspectee()));
}
if (gc_stats() != NULL) {
jsobj.AddProperty("reason", Heap::GCReasonToString(gc_stats()->reason_));
isolate()->heap()->PrintToJSONObject(Heap::kNew, &jsobj);
isolate()->heap()->PrintToJSONObject(Heap::kOld, &jsobj);
}
if (bytes() != NULL) {
jsobj.AddPropertyBase64("bytes", bytes(), bytes_length());
}
if (kind() == kLogging) {
JSONObject logRecord(&jsobj, "logRecord");
logRecord.AddProperty64("sequenceNumber", log_record_.sequence_number);
logRecord.AddPropertyTimeMillis("time", log_record_.timestamp);
logRecord.AddProperty64("level", log_record_.level);
logRecord.AddProperty("loggerName", *(log_record_.name));
logRecord.AddProperty("message", *(log_record_.message));
logRecord.AddProperty("zone", *(log_record_.zone));
logRecord.AddProperty("error", *(log_record_.error));
logRecord.AddProperty("stackTrace", *(log_record_.stack_trace));
}
}
void ServiceEvent::PrintJSONHeader(JSONObject* jsobj) const {
ASSERT(jsobj != NULL);
jsobj->AddProperty("type", "Event");
jsobj->AddProperty("kind", KindAsCString());
if (kind() == kVMUpdate) {
jsobj->AddPropertyVM("vm");
} else {
jsobj->AddProperty("isolate", isolate());
}
ASSERT(timestamp_ != -1);
jsobj->AddPropertyTimeMillis("timestamp", timestamp_);
}
} // namespace dart