diff --git a/runtime/platform/text_buffer.cc b/runtime/platform/text_buffer.cc index b9c6ac7515b..1536dac13b3 100644 --- a/runtime/platform/text_buffer.cc +++ b/runtime/platform/text_buffer.cc @@ -48,6 +48,14 @@ void TextBuffer::AddChar(char ch) { } +void TextBuffer::AddRaw(const uint8_t* buffer, + intptr_t buffer_length) { + EnsureCapacity(buffer_length); + memmove(&buf_[msg_len_], buffer, buffer_length); + msg_len_ += buffer_length; + buf_[msg_len_] = '\0'; +} + intptr_t TextBuffer::Printf(const char* format, ...) { va_list args; va_start(args, format); diff --git a/runtime/platform/text_buffer.h b/runtime/platform/text_buffer.h index f8f0c2fcc8c..1908ecb05cf 100644 --- a/runtime/platform/text_buffer.h +++ b/runtime/platform/text_buffer.h @@ -23,6 +23,8 @@ class TextBuffer : ValueObject { void EscapeAndAddCodeUnit(uint32_t cu); void AddString(const char* s); void AddEscapedString(const char* s); + void AddRaw(const uint8_t* buffer, + intptr_t buffer_length); void Clear(); diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index 8f3cb9764c5..12a7fdb29e5 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -5890,8 +5890,7 @@ static void DataStreamToConsumer(Dart_StreamConsumer consumer, static bool StreamTraceEvents(Dart_StreamConsumer consumer, void* user_data, - JSONStream* js, - bool insert_comma) { + JSONStream* js) { ASSERT(js != NULL); // Steal output from JSONStream. char* output = NULL; @@ -5909,13 +5908,8 @@ static bool StreamTraceEvents(Dart_StreamConsumer consumer, // Replace the ']' with the null character. output[output_length - 1] = '\0'; char* start = &output[1]; - if (insert_comma) { - output[0] = ','; - start = &output[0]; - } else { - // We are skipping the '['. - output_length -= 1; - } + // We are skipping the '['. + output_length -= 1; DataStreamToConsumer(consumer, user_data, @@ -5952,7 +5946,7 @@ DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer, IsolateTimelineEventFilter filter(isolate->main_port()); timeline_recorder->PrintTraceEvent(&js, &filter); StartStreamToConsumer(consumer, user_data, "timeline"); - bool success = StreamTraceEvents(consumer, user_data, &js, false); + bool success = StreamTraceEvents(consumer, user_data, &js); FinishStreamToConsumer(consumer, user_data, "timeline"); return success; } @@ -5989,17 +5983,12 @@ DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer, return false; } Timeline::ReclaimCachedBlocksFromThreads(); + bool success = false; JSONStream js; TimelineEventFilter filter; timeline_recorder->PrintTraceEvent(&js, &filter); StartStreamToConsumer(consumer, user_data, "timeline"); - bool success = false; - if (Timeline::get_get_timeline_cb() != NULL) { - if (Timeline::get_get_timeline_cb()(consumer, user_data)) { - success = true; - } - } - if (StreamTraceEvents(consumer, user_data, &js, success)) { + if (StreamTraceEvents(consumer, user_data, &js)) { success = true; } FinishStreamToConsumer(consumer, user_data, "timeline"); diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc index 6c6fb8f9a92..4be3fa90039 100644 --- a/runtime/vm/dart_api_impl_test.cc +++ b/runtime/vm/dart_api_impl_test.cc @@ -9827,7 +9827,7 @@ TEST_CASE(Timeline_Dart_EmbedderTimelineGetTimeline) { bool success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data); EXPECT(success); - EXPECT_SUBSTRING("HELLO FROM EMBEDDER,{\"name\":\"testDurationEvent\"", + EXPECT_SUBSTRING("}},HELLO FROM EMBEDDER", data.buffer); // Free buffer allocated by AppendStreamConsumer diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc index a68d87d8553..a721c7e9bb0 100644 --- a/runtime/vm/json_stream.cc +++ b/runtime/vm/json_stream.cc @@ -20,6 +20,23 @@ namespace dart { #ifndef PRODUCT +void AppendJSONStreamConsumer(Dart_StreamConsumer_State state, + const char* stream_name, + const uint8_t* buffer, + intptr_t buffer_length, + void* user_data) { + if ((state == Dart_StreamConsumer_kStart) || + (state == Dart_StreamConsumer_kFinish)) { + // Ignore. + return; + } + ASSERT(state == Dart_StreamConsumer_kData); + JSONStream* js = reinterpret_cast(user_data); + ASSERT(js != NULL); + js->AppendSerializedObject(buffer, buffer_length); +} + + DECLARE_FLAG(bool, trace_service); JSONStream::JSONStream(intptr_t buf_size) @@ -263,6 +280,11 @@ void JSONStream::AppendSerializedObject(const char* serialized_object) { } +void JSONStream::AppendSerializedObject(const uint8_t* buffer, + intptr_t buffer_length) { + buffer_.AddRaw(buffer, buffer_length); +} + void JSONStream::AppendSerializedObject(const char* property_name, const char* serialized_object) { PrintCommaIfNeeded(); diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h index 6c4f23e32bc..5b020b0d660 100644 --- a/runtime/vm/json_stream.h +++ b/runtime/vm/json_stream.h @@ -55,6 +55,12 @@ enum JSONRpcErrorCode { kIsolateMustBeRunnable = 105, }; +// Expected that user_data is a JSONStream*. +void AppendJSONStreamConsumer(Dart_StreamConsumer_State state, + const char* stream_name, + const uint8_t* buffer, + intptr_t buffer_length, + void* user_data); class JSONStream : ValueObject { public: @@ -129,6 +135,12 @@ class JSONStream : ValueObject { // Append |serialized_object| to the stream. void AppendSerializedObject(const char* serialized_object); + void PrintCommaIfNeeded(); + + // Append |buffer| to the stream. + void AppendSerializedObject(const uint8_t* buffer, + intptr_t buffer_length); + // Append |serialized_object| to the stream with |property_name|. void AppendSerializedObject(const char* property_name, const char* serialized_object); @@ -196,7 +208,6 @@ class JSONStream : ValueObject { const TimelineEventBlock* timeline_event_block); void PrintPropertyVM(const char* name, bool ref = true); void PrintPropertyName(const char* name); - void PrintCommaIfNeeded(); bool NeedComma(); bool AddDartString(const String& s, intptr_t offset, intptr_t count); diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc index 7c5b49f81a1..e8c4f5d959a 100644 --- a/runtime/vm/json_test.cc +++ b/runtime/vm/json_test.cc @@ -315,6 +315,33 @@ TEST_CASE(JSON_JSONStream_Params) { EXPECT(!js.ParamIs("dog", "banana")); } + +TEST_CASE(JSON_JSONStream_AppendJSONStreamConsumer) { + JSONStream js; + + { + JSONObject obj(&js); + { + JSONArray arr(&obj, "test"); + const char* test_data = "{a, b, c},"; + AppendJSONStreamConsumer(Dart_StreamConsumer_kData, "", + reinterpret_cast(&test_data[0]), + strlen(test_data), + &js); + AppendJSONStreamConsumer(Dart_StreamConsumer_kData, "", + reinterpret_cast(&test_data[0]), + strlen(test_data), + &js); + AppendJSONStreamConsumer(Dart_StreamConsumer_kData, "", + reinterpret_cast(&test_data[0]), + strlen(test_data) - 1, + &js); + } + } + + EXPECT_STREQ("{\"test\":[{a, b, c},{a, b, c},{a, b, c}]}", js.ToCString()); +} + #endif // !PRODUCT } // namespace dart diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc index 4072d806894..cd0b0fdb8ef 100644 --- a/runtime/vm/timeline.cc +++ b/runtime/vm/timeline.cc @@ -1027,6 +1027,14 @@ void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) { } +void TimelineEventRecorder::PrintEmbedderJSONEvents(JSONStream* events) { + if (Timeline::get_get_timeline_cb() != NULL) { + events->PrintCommaIfNeeded(); + Timeline::get_get_timeline_cb()(AppendJSONStreamConsumer, events); + } +} + + void TimelineEventRecorder::WriteTo(const char* directory) { if (!FLAG_support_service) { return; @@ -1166,6 +1174,7 @@ void TimelineEventRingRecorder::PrintJSON(JSONStream* js, JSONArray events(&topLevel, "traceEvents"); PrintJSONMeta(&events); PrintJSONEvents(&events, filter); + PrintEmbedderJSONEvents(js); } } @@ -1177,6 +1186,7 @@ void TimelineEventRingRecorder::PrintTraceEvent(JSONStream* js, } JSONArray events(js); PrintJSONEvents(&events, filter); + PrintEmbedderJSONEvents(js); } @@ -1299,6 +1309,7 @@ void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js, JSONArray events(&topLevel, "traceEvents"); PrintJSONMeta(&events); PrintJSONEvents(&events, filter); + PrintEmbedderJSONEvents(js); } } @@ -1311,6 +1322,7 @@ void TimelineEventEndlessRecorder::PrintTraceEvent( } JSONArray events(js); PrintJSONEvents(&events, filter); + PrintEmbedderJSONEvents(js); } diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h index 3bd32dd24c2..9887aff721f 100644 --- a/runtime/vm/timeline.h +++ b/runtime/vm/timeline.h @@ -678,6 +678,7 @@ class TimelineEventRecorder { void PrintJSONMeta(JSONArray* array) const; TimelineEvent* ThreadBlockStartEvent(); void ThreadBlockCompleteEvent(TimelineEvent* event); + void PrintEmbedderJSONEvents(JSONStream* events); Mutex lock_; uintptr_t async_id_;