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