| // 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 |