json: Optimize writing a bit.

This improves the responsiveness of certain APIs.
This commit is contained in:
Unknown W. Brackets 2018-04-30 20:38:39 -07:00
parent ccea863f00
commit fc8ad3b47b
7 changed files with 121 additions and 91 deletions

View file

@ -91,7 +91,7 @@ void WebSocketCPUStatus(DebuggerRequest &req) {
json.writeBool("stepping", PSP_IsInited() && Core_IsStepping() && coreState != CORE_POWERDOWN); json.writeBool("stepping", PSP_IsInited() && Core_IsStepping() && coreState != CORE_POWERDOWN);
json.writeBool("paused", GetUIState() != UISTATE_INGAME); json.writeBool("paused", GetUIState() != UISTATE_INGAME);
// Avoid NULL deference. // Avoid NULL deference.
json.writeFloat("pc", PSP_IsInited() ? currentMIPS->pc : 0); json.writeUint("pc", PSP_IsInited() ? currentMIPS->pc : 0);
// A double ought to be good enough for a 156 day debug session. // A double ought to be good enough for a 156 day debug session.
json.writeFloat("ticks", PSP_IsInited() ? CoreTiming::GetTicks() : 0); json.writeFloat("ticks", PSP_IsInited() ? CoreTiming::GetTicks() : 0);
} }
@ -131,11 +131,11 @@ void WebSocketCPUGetAllRegs(DebuggerRequest &req) {
json.pushArray("uintValues"); json.pushArray("uintValues");
// Writing as floating point to avoid negatives. Actually double, so safe. // Writing as floating point to avoid negatives. Actually double, so safe.
for (int r = 0; r < total; ++r) for (int r = 0; r < total; ++r)
json.writeFloat(currentDebugMIPS->GetRegValue(c, r)); json.writeUint(currentDebugMIPS->GetRegValue(c, r));
if (c == 0) { if (c == 0) {
json.writeFloat(currentDebugMIPS->GetPC()); json.writeUint(currentDebugMIPS->GetPC());
json.writeFloat(currentDebugMIPS->GetHi()); json.writeUint(currentDebugMIPS->GetHi());
json.writeFloat(currentDebugMIPS->GetLo()); json.writeUint(currentDebugMIPS->GetLo());
} }
json.pop(); json.pop();
@ -267,7 +267,7 @@ void WebSocketCPUGetReg(DebuggerRequest &req) {
JsonWriter &json = req.Respond(); JsonWriter &json = req.Respond();
json.writeInt("category", cat); json.writeInt("category", cat);
json.writeInt("register", reg); json.writeInt("register", reg);
json.writeFloat("uintValue", val); json.writeUint("uintValue", val);
json.writeString("floatValue", RegValueAsFloat(val)); json.writeString("floatValue", RegValueAsFloat(val));
} }
@ -335,7 +335,7 @@ void WebSocketCPUSetReg(DebuggerRequest &req) {
// Repeat it back just to avoid confusion on how it parsed. // Repeat it back just to avoid confusion on how it parsed.
json.writeInt("category", cat); json.writeInt("category", cat);
json.writeInt("register", reg); json.writeInt("register", reg);
json.writeFloat("uintValue", val); json.writeUint("uintValue", val);
json.writeString("floatValue", RegValueAsFloat(val)); json.writeString("floatValue", RegValueAsFloat(val));
} }
@ -368,6 +368,6 @@ void WebSocketCPUEvaluate(DebuggerRequest &req) {
} }
JsonWriter &json = req.Respond(); JsonWriter &json = req.Respond();
json.writeFloat("uintValue", val); json.writeUint("uintValue", val);
json.writeString("floatValue", RegValueAsFloat(val)); json.writeString("floatValue", RegValueAsFloat(val));
} }

View file

@ -63,17 +63,17 @@ void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLi
else if (l.type == DISTYPE_OTHER) else if (l.type == DISTYPE_OTHER)
json.writeString("type", "other"); json.writeString("type", "other");
json.writeFloat("address", addr); json.writeUint("address", addr);
json.writeInt("addressSize", l.totalSize); json.writeInt("addressSize", l.totalSize);
json.writeFloat("encoding", Memory::IsValidAddress(addr) ? Memory::Read_Instruction(addr).encoding : 0); json.writeUint("encoding", Memory::IsValidAddress(addr) ? Memory::Read_Instruction(addr).encoding : 0);
if (l.totalSize >= 8 && Memory::IsValidRange(addr, l.totalSize)) { if (l.totalSize >= 8 && Memory::IsValidRange(addr, l.totalSize)) {
json.pushArray("macroEncoding"); json.pushArray("macroEncoding");
for (u32 off = 0; off < l.totalSize; off += 4) { for (u32 off = 0; off < l.totalSize; off += 4) {
json.writeFloat(Memory::Read_Instruction(addr + off).encoding); json.writeUint(Memory::Read_Instruction(addr + off).encoding);
} }
json.pop(); json.pop();
} else { } else {
json.writeRaw("macroEncoding", "null"); json.writeNull("macroEncoding");
} }
int c = currentDebugMIPS->getColor(addr) & 0x00FFFFFF; int c = currentDebugMIPS->getColor(addr) & 0x00FFFFFF;
json.writeString("backgroundColor", StringFromFormat("#%02x%02x%02x", c & 0xFF, (c >> 8) & 0xFF, c >> 16)); json.writeString("backgroundColor", StringFromFormat("#%02x%02x%02x", c & 0xFF, (c >> 8) & 0xFF, c >> 16));
@ -82,7 +82,7 @@ void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLi
const std::string addressSymbol = g_symbolMap->GetLabelString(addr); const std::string addressSymbol = g_symbolMap->GetLabelString(addr);
if (addressSymbol.empty()) if (addressSymbol.empty())
json.writeRaw("symbol", "null"); json.writeNull("symbol");
else else
json.writeString("symbol", addressSymbol); json.writeString("symbol", addressSymbol);
@ -95,10 +95,10 @@ void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLi
if (cond) if (cond)
json.writeString("expression", cond->expressionString); json.writeString("expression", cond->expressionString);
else else
json.writeRaw("expression", "null"); json.writeNull("expression");
json.pop(); json.pop();
} else { } else {
json.writeRaw("breakpoint", "null"); json.writeNull("breakpoint");
} }
json.writeBool("isCurrentPC", currentDebugMIPS->GetPC() == addr); json.writeBool("isCurrentPC", currentDebugMIPS->GetPC() == addr);
@ -107,70 +107,70 @@ void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLi
std::string targetSymbol; std::string targetSymbol;
if (!l.info.isBranchToRegister) { if (!l.info.isBranchToRegister) {
targetSymbol = g_symbolMap->GetLabelString(l.info.branchTarget); targetSymbol = g_symbolMap->GetLabelString(l.info.branchTarget);
json.writeFloat("targetAddress", l.info.branchTarget); json.writeUint("targetAddress", l.info.branchTarget);
json.writeRaw("register", "null"); json.writeNull("register");
} else { } else {
json.writeRaw("targetAddress", "null"); json.writeNull("targetAddress");
json.writeInt("register", l.info.branchRegisterNum); json.writeInt("register", l.info.branchRegisterNum);
} }
json.writeBool("isLinked", l.info.isLinkedBranch); json.writeBool("isLinked", l.info.isLinkedBranch);
json.writeBool("isLikely", l.info.isLikelyBranch); json.writeBool("isLikely", l.info.isLikelyBranch);
if (targetSymbol.empty()) if (targetSymbol.empty())
json.writeRaw("symbol", "null"); json.writeNull("symbol");
else else
json.writeString("symbol", targetSymbol); json.writeString("symbol", targetSymbol);
json.pop(); json.pop();
} else { } else {
json.writeRaw("branch", "null"); json.writeNull("branch");
} }
if (l.info.hasRelevantAddress) { if (l.info.hasRelevantAddress) {
json.pushDict("relevantData"); json.pushDict("relevantData");
json.writeFloat("address", l.info.relevantAddress); json.writeUint("address", l.info.relevantAddress);
if (Memory::IsValidRange(l.info.relevantAddress, 4)) if (Memory::IsValidRange(l.info.relevantAddress, 4))
json.writeFloat("uintValue", Memory::ReadUnchecked_U32(l.info.relevantAddress)); json.writeUint("uintValue", Memory::ReadUnchecked_U32(l.info.relevantAddress));
else else
json.writeRaw("uintValue", "null"); json.writeNull("uintValue");
json.pop(); json.pop();
} else { } else {
json.writeRaw("relevantData", "null"); json.writeNull("relevantData");
} }
if (l.info.isConditional) if (l.info.isConditional)
json.writeBool("conditionMet", l.info.conditionMet); json.writeBool("conditionMet", l.info.conditionMet);
else else
json.writeRaw("conditionMet", "null"); json.writeNull("conditionMet");
if (l.info.isDataAccess) { if (l.info.isDataAccess) {
json.pushDict("dataAccess"); json.pushDict("dataAccess");
json.writeFloat("address", l.info.dataAddress); json.writeUint("address", l.info.dataAddress);
json.writeInt("size", l.info.dataSize); json.writeInt("size", l.info.dataSize);
std::string dataSymbol = g_symbolMap->GetLabelString(l.info.dataAddress); std::string dataSymbol = g_symbolMap->GetLabelString(l.info.dataAddress);
std::string valueSymbol; std::string valueSymbol;
if (!Memory::IsValidRange(l.info.dataAddress, l.info.dataSize)) if (!Memory::IsValidRange(l.info.dataAddress, l.info.dataSize))
json.writeRaw("uintValue", "null"); json.writeNull("uintValue");
else if (l.info.dataSize == 1) else if (l.info.dataSize == 1)
json.writeFloat("uintValue", Memory::ReadUnchecked_U8(l.info.dataAddress)); json.writeUint("uintValue", Memory::ReadUnchecked_U8(l.info.dataAddress));
else if (l.info.dataSize == 2) else if (l.info.dataSize == 2)
json.writeFloat("uintValue", Memory::ReadUnchecked_U16(l.info.dataAddress)); json.writeUint("uintValue", Memory::ReadUnchecked_U16(l.info.dataAddress));
else if (l.info.dataSize >= 4) { else if (l.info.dataSize >= 4) {
u32 data = Memory::ReadUnchecked_U32(l.info.dataAddress); u32 data = Memory::ReadUnchecked_U32(l.info.dataAddress);
valueSymbol = g_symbolMap->GetLabelString(data); valueSymbol = g_symbolMap->GetLabelString(data);
json.writeFloat("uintValue", data); json.writeUint("uintValue", data);
} }
if (!dataSymbol.empty()) if (!dataSymbol.empty())
json.writeString("symbol", dataSymbol); json.writeString("symbol", dataSymbol);
else else
json.writeRaw("symbol", "null"); json.writeNull("symbol");
if (!valueSymbol.empty()) if (!valueSymbol.empty())
json.writeString("valueSymbol", valueSymbol); json.writeString("valueSymbol", valueSymbol);
else else
json.writeRaw("valueSymbol", "null"); json.writeNull("valueSymbol");
json.pop(); json.pop();
} else { } else {
json.writeRaw("dataAccess", "null"); json.writeNull("dataAccess");
} }
json.pop(); json.pop();
@ -178,8 +178,8 @@ void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLi
void WebSocketDisasmState::WriteBranchGuide(JsonWriter &json, const BranchLine &l) { void WebSocketDisasmState::WriteBranchGuide(JsonWriter &json, const BranchLine &l) {
json.pushDict(); json.pushDict();
json.writeFloat("top", l.first); json.writeUint("top", l.first);
json.writeFloat("bottom", l.second); json.writeUint("bottom", l.second);
if (l.type == LINE_UP) if (l.type == LINE_UP)
json.writeString("direction", "up"); json.writeString("direction", "up");
else if (l.type == LINE_DOWN) else if (l.type == LINE_DOWN)
@ -279,8 +279,8 @@ void WebSocketDisasmState::Disasm(DebuggerRequest &req) {
JsonWriter &json = req.Respond(); JsonWriter &json = req.Respond();
json.pushDict("range"); json.pushDict("range");
json.writeFloat("start", start); json.writeUint("start", start);
json.writeFloat("end", end); json.writeUint("end", end);
json.pop(); json.pop();
json.pushArray("lines"); json.pushArray("lines");

View file

@ -34,7 +34,7 @@ struct GameStatusEvent {
j.writeString("title", g_paramSFO.GetValueString("TITLE")); j.writeString("title", g_paramSFO.GetValueString("TITLE"));
j.pop(); j.pop();
} else { } else {
j.writeRaw("game", "null"); j.writeNull("game");
} }
j.end(); j.end();
return j.str(); return j.str();

View file

@ -46,7 +46,7 @@ void WebSocketGameStatus(DebuggerRequest &req) {
json.writeString("title", g_paramSFO.GetValueString("TITLE")); json.writeString("title", g_paramSFO.GetValueString("TITLE"));
json.pop(); json.pop();
} else { } else {
json.writeRaw("game", "null"); json.writeNull("game");
} }
json.writeBool("paused", GetUIState() == UISTATE_PAUSEMENU); json.writeBool("paused", GetUIState() == UISTATE_PAUSEMENU);
} }

View file

@ -27,7 +27,7 @@ struct CPUSteppingEvent {
JsonWriter j; JsonWriter j;
j.begin(); j.begin();
j.writeString("event", "cpu.stepping"); j.writeString("event", "cpu.stepping");
j.writeFloat("pc", currentMIPS->pc); j.writeUint("pc", currentMIPS->pc);
// A double ought to be good enough for a 156 day debug session. // A double ought to be good enough for a 156 day debug session.
j.writeFloat("ticks", CoreTiming::GetTicks()); j.writeFloat("ticks", CoreTiming::GetTicks());
j.end(); j.end();

View file

@ -84,10 +84,10 @@ void JsonWriter::pushDict() {
stack_.push_back(StackEntry(DICT)); stack_.push_back(StackEntry(DICT));
} }
void JsonWriter::pushDict(const char *name) { void JsonWriter::pushDict(const std::string &name) {
str_ << comma() << indent() << "\""; str_ << comma() << indent() << "\"";
writeEscapedString(name); writeEscapedString(name);
str_ << "\": {"; str_ << (pretty_ ? "\": {" : "\":{");
stack_.back().first = false; stack_.back().first = false;
stack_.push_back(StackEntry(DICT)); stack_.push_back(StackEntry(DICT));
} }
@ -98,10 +98,10 @@ void JsonWriter::pushArray() {
stack_.push_back(StackEntry(ARRAY)); stack_.push_back(StackEntry(ARRAY));
} }
void JsonWriter::pushArray(const char *name) { void JsonWriter::pushArray(const std::string &name) {
str_ << comma() << indent() << "\""; str_ << comma() << indent() << "\"";
writeEscapedString(name); writeEscapedString(name);
str_ << "\": ["; str_ << (pretty_ ? "\": [" : "\":[");
stack_.push_back(StackEntry(ARRAY)); stack_.push_back(StackEntry(ARRAY));
} }
@ -110,10 +110,10 @@ void JsonWriter::writeBool(bool value) {
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeBool(const char *name, bool value) { void JsonWriter::writeBool(const std::string &name, bool value) {
str_ << comma() << indent() << "\""; str_ << comma() << indent() << "\"";
writeEscapedString(name); writeEscapedString(name);
str_ << "\": " << (value ? "true" : "false"); str_ << (pretty_ ? "\": " : "\":") << (value ? "true" : "false");
stack_.back().first = false; stack_.back().first = false;
} }
@ -122,10 +122,22 @@ void JsonWriter::writeInt(int value) {
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeInt(const char *name, int value) { void JsonWriter::writeInt(const std::string &name, int value) {
str_ << comma() << indent() << "\""; str_ << comma() << indent() << "\"";
writeEscapedString(name); writeEscapedString(name);
str_ << "\": " << value; str_ << (pretty_ ? "\": " : "\":") << value;
stack_.back().first = false;
}
void JsonWriter::writeUint(uint32_t value) {
str_ << arrayComma() << arrayIndent() << value;
stack_.back().first = false;
}
void JsonWriter::writeUint(const std::string &name, uint32_t value) {
str_ << comma() << indent() << "\"";
writeEscapedString(name);
str_ << (pretty_ ? "\": " : "\":") << value;
stack_.back().first = false; stack_.back().first = false;
} }
@ -138,10 +150,10 @@ void JsonWriter::writeFloat(double value) {
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeFloat(const char *name, double value) { void JsonWriter::writeFloat(const std::string &name, double value) {
str_ << comma() << indent() << "\""; str_ << comma() << indent() << "\"";
writeEscapedString(name); writeEscapedString(name);
str_ << "\": "; str_ << (pretty_ ? "\": " : "\":");
if (std::isfinite(value)) if (std::isfinite(value))
str_ << value; str_ << value;
else else
@ -149,14 +161,14 @@ void JsonWriter::writeFloat(const char *name, double value) {
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeString(const char *value) { void JsonWriter::writeString(const std::string &value) {
str_ << arrayComma() << arrayIndent() << "\""; str_ << arrayComma() << arrayIndent() << "\"";
writeEscapedString(value); writeEscapedString(value);
str_ << "\""; str_ << "\"";
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeString(const char *name, const char *value) { void JsonWriter::writeString(const std::string &name, const std::string &value) {
str_ << comma() << indent() << "\""; str_ << comma() << indent() << "\"";
writeEscapedString(name); writeEscapedString(name);
str_ << (pretty_ ? "\": \"" : "\":\""); str_ << (pretty_ ? "\": \"" : "\":\"");
@ -165,12 +177,12 @@ void JsonWriter::writeString(const char *name, const char *value) {
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeRaw(const char *value) { void JsonWriter::writeRaw(const std::string &value) {
str_ << arrayComma() << arrayIndent() << value; str_ << arrayComma() << arrayIndent() << value;
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeRaw(const char *name, const char *value) { void JsonWriter::writeRaw(const std::string &name, const std::string &value) {
str_ << comma() << indent() << "\""; str_ << comma() << indent() << "\"";
writeEscapedString(name); writeEscapedString(name);
str_ << (pretty_ ? "\": " : "\":"); str_ << (pretty_ ? "\": " : "\":");
@ -178,6 +190,18 @@ void JsonWriter::writeRaw(const char *name, const char *value) {
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeNull() {
str_ << arrayComma() << arrayIndent() << "null";
stack_.back().first = false;
}
void JsonWriter::writeNull(const std::string &name) {
str_ << comma() << indent() << "\"";
writeEscapedString(name);
str_ << (pretty_ ? "\": " : "\":") << "null";
stack_.back().first = false;
}
void JsonWriter::pop() { void JsonWriter::pop() {
BlockType type = stack_.back().type; BlockType type = stack_.back().type;
stack_.pop_back(); stack_.pop_back();
@ -197,33 +221,53 @@ void JsonWriter::pop() {
stack_.back().first = false; stack_.back().first = false;
} }
void JsonWriter::writeEscapedString(const char *str) { void JsonWriter::writeEscapedString(const std::string &str) {
size_t pos = 0; size_t pos = 0;
size_t len = strlen(str); const size_t len = str.size();
auto update = [&](size_t current, size_t skip = 0) { auto update = [&](size_t current, size_t skip = 0) {
size_t end = current; size_t end = current;
if (pos < end) if (pos < end)
str_ << std::string(str + pos, end - pos); str_ << str.substr(pos, end - pos);
pos = end + skip; pos = end + skip;
}; };
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
if (str[i] == '\\' || str[i] == '"' || str[i] == '/') { switch (str[i]) {
case '\\':
case '"':
case '/':
update(i); update(i);
str_ << '\\'; str_ << '\\';
} else if (str[i] == '\r') { break;
case '\r':
update(i, 1); update(i, 1);
str_ << "\\r"; str_ << "\\r";
} else if (str[i] == '\n') { break;
break;
case '\n':
update(i, 1); update(i, 1);
str_ << "\\n"; str_ << "\\n";
} else if (str[i] == '\t') { break;
break;
case '\t':
update(i, 1); update(i, 1);
str_ << "\\t"; str_ << "\\t";
} else if (str[i] < 32) { break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 11:
case 12: case 14: case 15: case 16: case 17: case 18: case 19: case 20:
case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28:
case 29: case 30: case 31:
update(i, 1); update(i, 1);
str_ << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (int)str[i] << std::dec << std::setw(0); str_ << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (int)str[i] << std::dec << std::setw(0);
break;
default:
break;
} }
} }
@ -273,7 +317,7 @@ std::string json_stringify(const JsonNode *node) {
static void json_stringify_object(JsonWriter &writer, const JsonNode *node) { static void json_stringify_object(JsonWriter &writer, const JsonNode *node) {
switch (node->value.getTag()) { switch (node->value.getTag()) {
case JSON_NULL: case JSON_NULL:
writer.writeRaw(node->key, "null"); writer.writeNull(node->key);
break; break;
case JSON_STRING: case JSON_STRING:
writer.writeString(node->key, node->value.toString()); writer.writeString(node->key, node->value.toString());

View file

@ -22,38 +22,24 @@ public:
void beginRaw(); void beginRaw();
void end(); void end();
void pushDict(); void pushDict();
void pushDict(const char *name); void pushDict(const std::string &name);
void pushArray(); void pushArray();
void pushArray(const char *name); void pushArray(const std::string &name);
void pop(); void pop();
void writeBool(bool value); void writeBool(bool value);
void writeBool(const char *name, bool value); void writeBool(const std::string &name, bool value);
void writeInt(int value); void writeInt(int value);
void writeInt(const char *name, int value); void writeInt(const std::string &name, int value);
void writeUint(uint32_t value);
void writeUint(const std::string &name, uint32_t value);
void writeFloat(double value); void writeFloat(double value);
void writeFloat(const char *name, double value); void writeFloat(const std::string &name, double value);
void writeString(const char *value); void writeString(const std::string &value);
void writeString(const char *name, const char *value); void writeString(const std::string &name, const std::string &value);
void writeString(const std::string &value) { void writeRaw(const std::string &value);
writeString(value.c_str()); void writeRaw(const std::string &name, const std::string &value);
} void writeNull();
void writeString(const char *name, const std::string &value) { void writeNull(const std::string &name);
writeString(name, value.c_str());
}
void writeString(const std::string &name, const std::string &value) {
writeString(name.c_str(), value.c_str());
}
void writeRaw(const char *value);
void writeRaw(const char *name, const char *value);
void writeRaw(const std::string &value) {
writeRaw(value.c_str());
}
void writeRaw(const char *name, const std::string &value) {
writeRaw(name, value.c_str());
}
void writeRaw(const std::string &name, const std::string &value) {
writeRaw(name.c_str(), value.c_str());
}
std::string str() const { std::string str() const {
return str_.str(); return str_.str();
@ -76,7 +62,7 @@ private:
const char *arrayComma() const; const char *arrayComma() const;
const char *indent() const; const char *indent() const;
const char *arrayIndent() const; const char *arrayIndent() const;
void writeEscapedString(const char *s); void writeEscapedString(const std::string &s);
enum BlockType { enum BlockType {
ARRAY, ARRAY,