| 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 | // for details. All rights reserved. Use of this source code is governed by a |
| 3 | // BSD-style license that can be found in the LICENSE file. |
| 4 | |
| 5 | #include "vm/service_event.h" |
| 6 | |
| 7 | #include "vm/debugger.h" |
| 8 | #include "vm/message_handler.h" |
| 9 | #include "vm/service_isolate.h" |
| 10 | #include "vm/timeline.h" |
| 11 | |
| 12 | namespace dart { |
| 13 | |
| 14 | #ifndef PRODUCT |
| 15 | |
| 16 | ServiceEvent::ServiceEvent(Isolate* isolate, EventKind event_kind) |
| 17 | : isolate_(isolate), |
| 18 | kind_(event_kind), |
| 19 | flag_name_(NULL), |
| 20 | flag_new_value_(NULL), |
| 21 | embedder_kind_(NULL), |
| 22 | embedder_stream_id_(NULL), |
| 23 | breakpoint_(NULL), |
| 24 | top_frame_(NULL), |
| 25 | timeline_event_block_(NULL), |
| 26 | extension_rpc_(NULL), |
| 27 | exception_(NULL), |
| 28 | reload_error_(NULL), |
| 29 | spawn_token_(NULL), |
| 30 | spawn_error_(NULL), |
| 31 | at_async_jump_(false), |
| 32 | inspectee_(NULL), |
| 33 | gc_stats_(NULL), |
| 34 | bytes_(NULL), |
| 35 | bytes_length_(0), |
| 36 | timestamp_(OS::GetCurrentTimeMillis()) { |
| 37 | // We should never generate events for the vm or service isolates. |
| 38 | ASSERT(isolate_ != Dart::vm_isolate()); |
| 39 | ASSERT(isolate == NULL || FLAG_show_invisible_isolates || |
| 40 | !Isolate::IsVMInternalIsolate(isolate)); |
| 41 | |
| 42 | if ((event_kind == ServiceEvent::kPauseStart) || |
| 43 | (event_kind == ServiceEvent::kPauseExit)) { |
| 44 | timestamp_ = isolate->message_handler()->paused_timestamp(); |
| 45 | } else if (event_kind == ServiceEvent::kResume) { |
| 46 | timestamp_ = isolate->last_resume_timestamp(); |
| 47 | } |
| 48 | ASSERT(timestamp_ > -1); |
| 49 | } |
| 50 | |
| 51 | void ServiceEvent::UpdateTimestamp() { |
| 52 | timestamp_ = OS::GetCurrentTimeMillis(); |
| 53 | } |
| 54 | |
| 55 | const char* ServiceEvent::KindAsCString() const { |
| 56 | switch (kind()) { |
| 57 | case kVMUpdate: |
| 58 | return "VMUpdate" ; |
| 59 | case kVMFlagUpdate: |
| 60 | return "VMFlagUpdate" ; |
| 61 | case kIsolateStart: |
| 62 | return "IsolateStart" ; |
| 63 | case kIsolateRunnable: |
| 64 | return "IsolateRunnable" ; |
| 65 | case kIsolateExit: |
| 66 | return "IsolateExit" ; |
| 67 | case kIsolateUpdate: |
| 68 | return "IsolateUpdate" ; |
| 69 | case kServiceExtensionAdded: |
| 70 | return "ServiceExtensionAdded" ; |
| 71 | case kIsolateReload: |
| 72 | return "IsolateReload" ; |
| 73 | case kPauseStart: |
| 74 | return "PauseStart" ; |
| 75 | case kPauseExit: |
| 76 | return "PauseExit" ; |
| 77 | case kPauseBreakpoint: |
| 78 | return "PauseBreakpoint" ; |
| 79 | case kPauseInterrupted: |
| 80 | return "PauseInterrupted" ; |
| 81 | case kPauseException: |
| 82 | return "PauseException" ; |
| 83 | case kPausePostRequest: |
| 84 | return "PausePostRequest" ; |
| 85 | case kNone: |
| 86 | return "None" ; |
| 87 | case kResume: |
| 88 | return "Resume" ; |
| 89 | case kBreakpointAdded: |
| 90 | return "BreakpointAdded" ; |
| 91 | case kBreakpointResolved: |
| 92 | return "BreakpointResolved" ; |
| 93 | case kBreakpointRemoved: |
| 94 | return "BreakpointRemoved" ; |
| 95 | case kGC: |
| 96 | return "GC" ; // TODO(koda): Change to GarbageCollected. |
| 97 | case kInspect: |
| 98 | return "Inspect" ; |
| 99 | case kEmbedder: |
| 100 | return embedder_kind(); |
| 101 | case kLogging: |
| 102 | return "Logging" ; |
| 103 | case kDebuggerSettingsUpdate: |
| 104 | return "_DebuggerSettingsUpdate" ; |
| 105 | case kIllegal: |
| 106 | return "Illegal" ; |
| 107 | case kExtension: |
| 108 | return "Extension" ; |
| 109 | case kTimelineEvents: |
| 110 | return "TimelineEvents" ; |
| 111 | case kTimelineStreamSubscriptionsUpdate: |
| 112 | return "TimelineStreamSubscriptionsUpdate" ; |
| 113 | default: |
| 114 | UNREACHABLE(); |
| 115 | return "Unknown" ; |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | const StreamInfo* ServiceEvent::stream_info() const { |
| 120 | switch (kind()) { |
| 121 | case kVMUpdate: |
| 122 | case kVMFlagUpdate: |
| 123 | return &Service::vm_stream; |
| 124 | |
| 125 | case kIsolateStart: |
| 126 | case kIsolateRunnable: |
| 127 | case kIsolateExit: |
| 128 | case kIsolateUpdate: |
| 129 | case kIsolateReload: |
| 130 | case kServiceExtensionAdded: |
| 131 | return &Service::isolate_stream; |
| 132 | |
| 133 | case kPauseStart: |
| 134 | case kPauseExit: |
| 135 | case kPauseBreakpoint: |
| 136 | case kPauseInterrupted: |
| 137 | case kPauseException: |
| 138 | case kPausePostRequest: |
| 139 | case kNone: |
| 140 | case kResume: |
| 141 | case kBreakpointAdded: |
| 142 | case kBreakpointResolved: |
| 143 | case kBreakpointRemoved: |
| 144 | case kInspect: |
| 145 | case kDebuggerSettingsUpdate: |
| 146 | return &Service::debug_stream; |
| 147 | |
| 148 | case kGC: |
| 149 | return &Service::gc_stream; |
| 150 | |
| 151 | case kLogging: |
| 152 | return &Service::logging_stream; |
| 153 | |
| 154 | case kExtension: |
| 155 | return &Service::extension_stream; |
| 156 | |
| 157 | case kTimelineEvents: |
| 158 | case kTimelineStreamSubscriptionsUpdate: |
| 159 | return &Service::timeline_stream; |
| 160 | |
| 161 | case kEmbedder: |
| 162 | return NULL; |
| 163 | |
| 164 | default: |
| 165 | UNREACHABLE(); |
| 166 | return NULL; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | const char* ServiceEvent::stream_id() const { |
| 171 | const StreamInfo* stream = stream_info(); |
| 172 | if (stream == NULL) { |
| 173 | ASSERT(kind() == kEmbedder); |
| 174 | return embedder_stream_id_; |
| 175 | } else { |
| 176 | return stream->id(); |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | void ServiceEvent::PrintJSON(JSONStream* js) const { |
| 181 | JSONObject jsobj(js); |
| 182 | PrintJSONHeader(&jsobj); |
| 183 | if (kind() == kVMFlagUpdate) { |
| 184 | jsobj.AddProperty("flag" , flag_name()); |
| 185 | // For backwards compatibility, "new_value" is also provided. |
| 186 | // TODO(bkonyi): remove when service protocol major version is incremented. |
| 187 | ASSERT(SERVICE_PROTOCOL_MAJOR_VERSION == 3); |
| 188 | jsobj.AddProperty("new_value" , flag_new_value()); |
| 189 | jsobj.AddProperty("newValue" , flag_new_value()); |
| 190 | } |
| 191 | if (kind() == kIsolateReload) { |
| 192 | if (reload_error_ == NULL) { |
| 193 | jsobj.AddProperty("status" , "success" ); |
| 194 | } else { |
| 195 | jsobj.AddProperty("status" , "failure" ); |
| 196 | jsobj.AddProperty("reloadError" , *(reload_error())); |
| 197 | } |
| 198 | } |
| 199 | if (kind() == kServiceExtensionAdded) { |
| 200 | ASSERT(extension_rpc_ != NULL); |
| 201 | jsobj.AddProperty("extensionRPC" , extension_rpc_->ToCString()); |
| 202 | } |
| 203 | if (kind() == kPauseBreakpoint) { |
| 204 | JSONArray jsarr(&jsobj, "pauseBreakpoints" ); |
| 205 | // TODO(rmacnak): If we are paused at more than one breakpoint, |
| 206 | // provide it here. |
| 207 | if (breakpoint() != NULL) { |
| 208 | jsarr.AddValue(breakpoint()); |
| 209 | } |
| 210 | } else { |
| 211 | if (breakpoint() != NULL) { |
| 212 | jsobj.AddProperty("breakpoint" , breakpoint()); |
| 213 | } |
| 214 | } |
| 215 | if (kind() == kTimelineEvents) { |
| 216 | jsobj.AddProperty("timelineEvents" , timeline_event_block_); |
| 217 | } |
| 218 | if (kind() == kTimelineStreamSubscriptionsUpdate) { |
| 219 | JSONArray arr(&jsobj, "updatedStreams" ); |
| 220 | Timeline::PrintFlagsToJSONArray(&arr); |
| 221 | } |
| 222 | if (kind() == kDebuggerSettingsUpdate) { |
| 223 | JSONObject jssettings(&jsobj, "_debuggerSettings" ); |
| 224 | isolate()->debugger()->PrintSettingsToJSONObject(&jssettings); |
| 225 | } |
| 226 | #if !defined(DART_PRECOMPILED_RUNTIME) |
| 227 | if (top_frame() != nullptr) { |
| 228 | JSONObject jsFrame(&jsobj, "topFrame" ); |
| 229 | top_frame()->PrintToJSONObject(&jsFrame); |
| 230 | intptr_t index = 0; // Avoid ambiguity in call to AddProperty. |
| 231 | jsFrame.AddProperty("index" , index); |
| 232 | } |
| 233 | #endif |
| 234 | if (exception() != NULL) { |
| 235 | jsobj.AddProperty("exception" , *(exception())); |
| 236 | } |
| 237 | if (at_async_jump()) { |
| 238 | jsobj.AddProperty("atAsyncSuspension" , true); |
| 239 | } |
| 240 | if (inspectee() != NULL) { |
| 241 | jsobj.AddProperty("inspectee" , *(inspectee())); |
| 242 | } |
| 243 | if (gc_stats() != NULL) { |
| 244 | jsobj.AddProperty("reason" , Heap::GCReasonToString(gc_stats()->reason_)); |
| 245 | isolate()->heap()->PrintToJSONObject(Heap::kNew, &jsobj); |
| 246 | isolate()->heap()->PrintToJSONObject(Heap::kOld, &jsobj); |
| 247 | } |
| 248 | if (bytes() != NULL) { |
| 249 | jsobj.AddPropertyBase64("bytes" , bytes(), bytes_length()); |
| 250 | } |
| 251 | if (kind() == kLogging) { |
| 252 | JSONObject logRecord(&jsobj, "logRecord" ); |
| 253 | logRecord.AddProperty("type" , "LogRecord" ); |
| 254 | logRecord.AddProperty64("sequenceNumber" , log_record_.sequence_number); |
| 255 | logRecord.AddPropertyTimeMillis("time" , log_record_.timestamp); |
| 256 | logRecord.AddProperty64("level" , log_record_.level); |
| 257 | logRecord.AddProperty("loggerName" , *(log_record_.name)); |
| 258 | logRecord.AddProperty("message" , *(log_record_.message)); |
| 259 | logRecord.AddProperty("zone" , *(log_record_.zone)); |
| 260 | logRecord.AddProperty("error" , *(log_record_.error)); |
| 261 | logRecord.AddProperty("stackTrace" , *(log_record_.stack_trace)); |
| 262 | } |
| 263 | if (kind() == kExtension) { |
| 264 | js->AppendSerializedObject("extensionData" , |
| 265 | extension_event_.event_data->ToCString()); |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | void ServiceEvent::(JSONObject* jsobj) const { |
| 270 | ASSERT(jsobj != NULL); |
| 271 | jsobj->AddProperty("type" , "Event" ); |
| 272 | jsobj->AddProperty("kind" , KindAsCString()); |
| 273 | if (kind() == kExtension) { |
| 274 | ASSERT(extension_event_.event_kind != NULL); |
| 275 | jsobj->AddProperty("extensionKind" , |
| 276 | extension_event_.event_kind->ToCString()); |
| 277 | } |
| 278 | if (isolate() == NULL) { |
| 279 | jsobj->AddPropertyVM("vm" ); |
| 280 | } else { |
| 281 | jsobj->AddProperty("isolate" , isolate()); |
| 282 | } |
| 283 | ASSERT(timestamp_ != -1); |
| 284 | jsobj->AddPropertyTimeMillis("timestamp" , timestamp_); |
| 285 | } |
| 286 | |
| 287 | #endif // !PRODUCT |
| 288 | |
| 289 | } // namespace dart |
| 290 | |