summaryrefslogtreecommitdiff
path: root/source/Utility
diff options
context:
space:
mode:
Diffstat (limited to 'source/Utility')
-rw-r--r--source/Utility/CMakeLists.txt4
-rw-r--r--source/Utility/Connection.cpp14
-rw-r--r--source/Utility/IOObject.cpp15
-rw-r--r--source/Utility/JSON.cpp2
-rw-r--r--source/Utility/StructuredData.cpp286
-rw-r--r--source/Utility/Timer.cpp132
6 files changed, 452 insertions, 1 deletions
diff --git a/source/Utility/CMakeLists.txt b/source/Utility/CMakeLists.txt
index 31b14acda9629..78598562692bb 100644
--- a/source/Utility/CMakeLists.txt
+++ b/source/Utility/CMakeLists.txt
@@ -1,5 +1,6 @@
add_lldb_library(lldbUtility
Baton.cpp
+ Connection.cpp
ConstString.cpp
DataBufferHeap.cpp
DataBufferLLVM.cpp
@@ -8,6 +9,7 @@ add_lldb_library(lldbUtility
FastDemangle.cpp
FileSpec.cpp
History.cpp
+ IOObject.cpp
JSON.cpp
LLDBAssert.cpp
Log.cpp
@@ -26,8 +28,10 @@ add_lldb_library(lldbUtility
StringExtractorGDBRemote.cpp
StringLexer.cpp
StringList.cpp
+ StructuredData.cpp
TaskPool.cpp
TildeExpressionResolver.cpp
+ Timer.cpp
UserID.cpp
UriParser.cpp
UUID.cpp
diff --git a/source/Utility/Connection.cpp b/source/Utility/Connection.cpp
new file mode 100644
index 0000000000000..9f6114f6ed5de
--- /dev/null
+++ b/source/Utility/Connection.cpp
@@ -0,0 +1,14 @@
+//===-- Connection.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Connection.h"
+
+using namespace lldb_private;
+
+Connection::~Connection() = default;
diff --git a/source/Utility/IOObject.cpp b/source/Utility/IOObject.cpp
new file mode 100644
index 0000000000000..df7929c4f9110
--- /dev/null
+++ b/source/Utility/IOObject.cpp
@@ -0,0 +1,15 @@
+//===-- IOObject.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/IOObject.h"
+
+using namespace lldb_private;
+
+const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1;
+IOObject::~IOObject() = default;
diff --git a/source/Utility/JSON.cpp b/source/Utility/JSON.cpp
index cb23f140cbfe0..1520bc7c47ec7 100644
--- a/source/Utility/JSON.cpp
+++ b/source/Utility/JSON.cpp
@@ -191,7 +191,7 @@ JSONValue::SP JSONArray::GetObject(Index i) {
JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
-JSONParser::JSONParser(const char *cstr) : StringExtractor(cstr) {}
+JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {}
JSONParser::Token JSONParser::GetToken(std::string &value) {
StreamString error;
diff --git a/source/Utility/StructuredData.cpp b/source/Utility/StructuredData.cpp
new file mode 100644
index 0000000000000..9fc05354cfd3f
--- /dev/null
+++ b/source/Utility/StructuredData.cpp
@@ -0,0 +1,286 @@
+//===---------------------StructuredData.cpp ---------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/JSON.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/STLExtras.h" // for make_unique
+#include <cerrno>
+#include <cstdlib>
+#include <inttypes.h>
+#include <limits> // for numeric_limits
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Functions that use a JSONParser to parse JSON into StructuredData
+//----------------------------------------------------------------------
+static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
+static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
+static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
+
+StructuredData::ObjectSP
+StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
+ StructuredData::ObjectSP return_sp;
+ if (!input_spec.Exists()) {
+ error.SetErrorStringWithFormatv("input file {0} does not exist.",
+ input_spec);
+ return return_sp;
+ }
+
+ auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
+ if (!buffer_or_error) {
+ error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
+ input_spec.GetPath(),
+ buffer_or_error.getError().message());
+ return return_sp;
+ }
+
+ JSONParser json_parser(buffer_or_error.get()->getBuffer());
+ return_sp = ParseJSONValue(json_parser);
+ return return_sp;
+}
+
+static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
+ // The "JSONParser::Token::ObjectStart" token should have already been
+ // consumed by the time this function is called
+ auto dict_up = llvm::make_unique<StructuredData::Dictionary>();
+
+ std::string value;
+ std::string key;
+ while (1) {
+ JSONParser::Token token = json_parser.GetToken(value);
+
+ if (token == JSONParser::Token::String) {
+ key.swap(value);
+ token = json_parser.GetToken(value);
+ if (token == JSONParser::Token::Colon) {
+ StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
+ if (value_sp)
+ dict_up->AddItem(key, value_sp);
+ else
+ break;
+ }
+ } else if (token == JSONParser::Token::ObjectEnd) {
+ return StructuredData::ObjectSP(dict_up.release());
+ } else if (token == JSONParser::Token::Comma) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ return StructuredData::ObjectSP();
+}
+
+static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
+ // The "JSONParser::Token::ObjectStart" token should have already been
+ // consumed
+ // by the time this function is called
+ auto array_up = llvm::make_unique<StructuredData::Array>();
+
+ std::string value;
+ std::string key;
+ while (1) {
+ StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
+ if (value_sp)
+ array_up->AddItem(value_sp);
+ else
+ break;
+
+ JSONParser::Token token = json_parser.GetToken(value);
+ if (token == JSONParser::Token::Comma) {
+ continue;
+ } else if (token == JSONParser::Token::ArrayEnd) {
+ return StructuredData::ObjectSP(array_up.release());
+ } else {
+ break;
+ }
+ }
+ return StructuredData::ObjectSP();
+}
+
+static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
+ std::string value;
+ const JSONParser::Token token = json_parser.GetToken(value);
+ switch (token) {
+ case JSONParser::Token::ObjectStart:
+ return ParseJSONObject(json_parser);
+
+ case JSONParser::Token::ArrayStart:
+ return ParseJSONArray(json_parser);
+
+ case JSONParser::Token::Integer: {
+ uint64_t uval;
+ if (llvm::to_integer(value, uval, 0))
+ return std::make_shared<StructuredData::Integer>(uval);
+ } break;
+
+ case JSONParser::Token::Float: {
+ double val;
+ if (llvm::to_float(value, val))
+ return std::make_shared<StructuredData::Float>(val);
+ } break;
+
+ case JSONParser::Token::String:
+ return std::make_shared<StructuredData::String>(value);
+
+ case JSONParser::Token::True:
+ case JSONParser::Token::False:
+ return std::make_shared<StructuredData::Boolean>(token ==
+ JSONParser::Token::True);
+
+ case JSONParser::Token::Null:
+ return std::make_shared<StructuredData::Null>();
+
+ default:
+ break;
+ }
+ return StructuredData::ObjectSP();
+}
+
+StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
+ JSONParser json_parser(json_text.c_str());
+ StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
+ return object_sp;
+}
+
+StructuredData::ObjectSP
+StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
+ if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
+ std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
+ std::string key = match.first.str();
+ ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
+ if (value.get()) {
+ // Do we have additional words to descend? If not, return the
+ // value we're at right now.
+ if (match.second.empty()) {
+ return value;
+ } else {
+ return value->GetObjectForDotSeparatedPath(match.second);
+ }
+ }
+ return ObjectSP();
+ }
+
+ if (this->GetType() == lldb::eStructuredDataTypeArray) {
+ std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
+ if (match.second.size() == 0) {
+ return this->shared_from_this();
+ }
+ errno = 0;
+ uint64_t val = strtoul(match.second.str().c_str(), NULL, 10);
+ if (errno == 0) {
+ return this->GetAsArray()->GetItemAtIndex(val);
+ }
+ return ObjectSP();
+ }
+
+ return this->shared_from_this();
+}
+
+void StructuredData::Object::DumpToStdout(bool pretty_print) const {
+ StreamString stream;
+ Dump(stream, pretty_print);
+ llvm::outs() << stream.GetString();
+}
+
+void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
+ bool first = true;
+ s << "[";
+ if (pretty_print) {
+ s << "\n";
+ s.IndentMore();
+ }
+ for (const auto &item_sp : m_items) {
+ if (first) {
+ first = false;
+ } else {
+ s << ",";
+ if (pretty_print)
+ s << "\n";
+ }
+
+ if (pretty_print)
+ s.Indent();
+ item_sp->Dump(s, pretty_print);
+ }
+ if (pretty_print) {
+ s.IndentLess();
+ s.EOL();
+ s.Indent();
+ }
+ s << "]";
+}
+
+void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
+ s.Printf("%" PRIu64, m_value);
+}
+
+void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
+ s.Printf("%lg", m_value);
+}
+
+void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
+ if (m_value == true)
+ s.PutCString("true");
+ else
+ s.PutCString("false");
+}
+
+void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
+ std::string quoted;
+ const size_t strsize = m_value.size();
+ for (size_t i = 0; i < strsize; ++i) {
+ char ch = m_value[i];
+ if (ch == '"' || ch == '\\')
+ quoted.push_back('\\');
+ quoted.push_back(ch);
+ }
+ s.Printf("\"%s\"", quoted.c_str());
+}
+
+void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
+ bool first = true;
+ s << "{";
+ if (pretty_print) {
+ s << "\n";
+ s.IndentMore();
+ }
+ for (const auto &pair : m_dict) {
+ if (first)
+ first = false;
+ else {
+ s << ",";
+ if (pretty_print)
+ s << "\n";
+ }
+ if (pretty_print)
+ s.Indent();
+ s << "\"" << pair.first.AsCString() << "\" : ";
+ pair.second->Dump(s, pretty_print);
+ }
+ if (pretty_print) {
+ s.IndentLess();
+ s.EOL();
+ s.Indent();
+ }
+ s << "}";
+}
+
+void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
+ s << "null";
+}
+
+void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
+ s << "0x" << m_object;
+}
diff --git a/source/Utility/Timer.cpp b/source/Utility/Timer.cpp
new file mode 100644
index 0000000000000..fe7787458fa6d
--- /dev/null
+++ b/source/Utility/Timer.cpp
@@ -0,0 +1,132 @@
+//===-- Timer.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "lldb/Utility/Timer.h"
+#include "lldb/Utility/Stream.h"
+
+#include <algorithm>
+#include <map>
+#include <mutex>
+#include <utility> // for pair
+#include <vector>
+
+#include <assert.h> // for assert
+#include <stdarg.h> // for va_end, va_list, va_start
+#include <stdio.h>
+
+using namespace lldb_private;
+
+#define TIMER_INDENT_AMOUNT 2
+
+namespace {
+typedef std::vector<Timer *> TimerStack;
+static std::atomic<Timer::Category *> g_categories;
+} // end of anonymous namespace
+
+std::atomic<bool> Timer::g_quiet(true);
+std::atomic<unsigned> Timer::g_display_depth(0);
+static std::mutex &GetFileMutex() {
+ static std::mutex *g_file_mutex_ptr = new std::mutex();
+ return *g_file_mutex_ptr;
+}
+
+static TimerStack &GetTimerStackForCurrentThread() {
+ static thread_local TimerStack g_stack;
+ return g_stack;
+}
+
+Timer::Category::Category(const char *cat) : m_name(cat) {
+ m_nanos.store(0, std::memory_order_release);
+ Category *expected = g_categories;
+ do {
+ m_next = expected;
+ } while (!g_categories.compare_exchange_weak(expected, this));
+}
+
+void Timer::SetQuiet(bool value) { g_quiet = value; }
+
+Timer::Timer(Timer::Category &category, const char *format, ...)
+ : m_category(category), m_total_start(std::chrono::steady_clock::now()) {
+ TimerStack &stack = GetTimerStackForCurrentThread();
+
+ stack.push_back(this);
+ if (g_quiet && stack.size() <= g_display_depth) {
+ std::lock_guard<std::mutex> lock(GetFileMutex());
+
+ // Indent
+ ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "");
+ // Print formatted string
+ va_list args;
+ va_start(args, format);
+ ::vfprintf(stdout, format, args);
+ va_end(args);
+
+ // Newline
+ ::fprintf(stdout, "\n");
+ }
+}
+
+Timer::~Timer() {
+ using namespace std::chrono;
+
+ auto stop_time = steady_clock::now();
+ auto total_dur = stop_time - m_total_start;
+ auto timer_dur = total_dur - m_child_duration;
+
+ TimerStack &stack = GetTimerStackForCurrentThread();
+ if (g_quiet && stack.size() <= g_display_depth) {
+ std::lock_guard<std::mutex> lock(GetFileMutex());
+ ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n",
+ int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "",
+ duration<double>(total_dur).count(),
+ duration<double>(timer_dur).count());
+ }
+
+ assert(stack.back() == this);
+ stack.pop_back();
+ if (!stack.empty())
+ stack.back()->ChildDuration(total_dur);
+
+ // Keep total results for each category so we can dump results.
+ m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count();
+}
+
+void Timer::SetDisplayDepth(uint32_t depth) { g_display_depth = depth; }
+
+/* binary function predicate:
+ * - returns whether a person is less than another person
+ */
+
+typedef std::pair<const char *, uint64_t> TimerEntry;
+
+static bool CategoryMapIteratorSortCriterion(const TimerEntry &lhs,
+ const TimerEntry &rhs) {
+ return lhs.second > rhs.second;
+}
+
+void Timer::ResetCategoryTimes() {
+ for (Category *i = g_categories; i; i = i->m_next)
+ i->m_nanos.store(0, std::memory_order_release);
+}
+
+void Timer::DumpCategoryTimes(Stream *s) {
+ std::vector<TimerEntry> sorted;
+ for (Category *i = g_categories; i; i = i->m_next) {
+ uint64_t nanos = i->m_nanos.load(std::memory_order_acquire);
+ if (nanos)
+ sorted.push_back(std::make_pair(i->m_name, nanos));
+ }
+ if (sorted.empty())
+ return; // Later code will break without any elements.
+
+ // Sort by time
+ std::sort(sorted.begin(), sorted.end(), CategoryMapIteratorSortCriterion);
+
+ for (const auto &timer : sorted)
+ s->Printf("%.9f sec for %s\n", timer.second / 1000000000., timer.first);
+}