mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
Opt JsonStringifier
Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAKGKR Signed-off-by: xwcai98 <caixinwei5@huawei.com> Change-Id: I4445f3e7fbfa4c10e339e2e629551bd801856b8b
This commit is contained in:
parent
831eb9d630
commit
8a1dc43008
@ -140,8 +140,7 @@ JSTaggedValue FastJsonStringifier::SerializeJSONProperty(const JSHandle<JSTagged
|
||||
auto string = JSHandle<EcmaString>(thread_,
|
||||
EcmaStringAccessor::Flatten(thread_->GetEcmaVM(), strHandle));
|
||||
CString str = ConvertToString(*string, StringConvertedUsage::LOGICOPERATION);
|
||||
str = JsonHelper::ValueToQuotedString(str);
|
||||
result_ += str;
|
||||
JsonHelper::AppendValueToQuotedString(str, result_);
|
||||
return tagValue;
|
||||
}
|
||||
case JSType::JS_PRIMITIVE_REF: {
|
||||
@ -187,8 +186,7 @@ CString FastJsonStringifier::SerializeObjectKey(const JSHandle<JSTaggedValue> &k
|
||||
} else {
|
||||
str = ConvertToString(*JSTaggedValue::ToString(thread_, key), StringConvertedUsage::LOGICOPERATION);
|
||||
}
|
||||
str = JsonHelper::ValueToQuotedString(str);
|
||||
result_ += str;
|
||||
JsonHelper::AppendValueToQuotedString(str, result_);
|
||||
result_ += ":";
|
||||
|
||||
return str;
|
||||
@ -397,8 +395,7 @@ void FastJsonStringifier::SerializePrimitiveRef(const JSHandle<JSTaggedValue> &p
|
||||
auto priStr = JSTaggedValue::ToString(thread_, primitiveRef);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread_);
|
||||
CString str = ConvertToString(*priStr, StringConvertedUsage::LOGICOPERATION);
|
||||
str = JsonHelper::ValueToQuotedString(str);
|
||||
result_ += str;
|
||||
JsonHelper::AppendValueToQuotedString(str, result_);
|
||||
} else if (primitive.IsNumber()) {
|
||||
auto priNum = JSTaggedValue::ToNumber(thread_, primitiveRef);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread_);
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
namespace panda::ecmascript::base {
|
||||
constexpr unsigned char CODE_SPACE = 0x20;
|
||||
constexpr int FOUR_HEX = 4;
|
||||
constexpr char ZERO_FIRST = static_cast<char>(0xc0); // \u0000 => c0 80
|
||||
constexpr char ALONE_SURROGATE_3B_FIRST = static_cast<char>(0xed);
|
||||
constexpr char ALONE_SURROGATE_3B_SECOND_START = static_cast<char>(0xa0);
|
||||
@ -30,116 +29,91 @@ constexpr char ALONE_SURROGATE_3B_SECOND_END = static_cast<char>(0xbf);
|
||||
constexpr char ALONE_SURROGATE_3B_THIRD_START = static_cast<char>(0x80);
|
||||
constexpr char ALONE_SURROGATE_3B_THIRD_END = static_cast<char>(0xbf);
|
||||
|
||||
bool JsonHelper::IsFastValueToQuotedString(const char *value)
|
||||
bool JsonHelper::IsFastValueToQuotedString(const CString& str)
|
||||
{
|
||||
if (strpbrk(value, "\"\\\b\f\n\r\t") != nullptr) {
|
||||
return false;
|
||||
}
|
||||
while (*value != '\0') {
|
||||
if ((*value > 0 && *value < CODE_SPACE) || *value == ZERO_FIRST || *value == ALONE_SURROGATE_3B_FIRST) {
|
||||
return false;
|
||||
for (const auto ch : str) {
|
||||
switch (ch) {
|
||||
case '\"':
|
||||
case '\\':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case ZERO_FIRST:
|
||||
case ALONE_SURROGATE_3B_FIRST:
|
||||
return false;
|
||||
default:
|
||||
if (ch > 0 && ch < CODE_SPACE) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
value++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CString JsonHelper::ValueToQuotedString(CString str)
|
||||
// String values are wrapped in QUOTATION MARK (") code units. The code units " and \ are escaped with \ prefixes.
|
||||
// Control characters code units are replaced with escape sequences \uHHHH, or with the shorter forms,
|
||||
// \b (BACKSPACE), \f (FORM FEED), \n (LINE FEED), \r (CARRIAGE RETURN), \t (CHARACTER TABULATION).
|
||||
void JsonHelper::AppendValueToQuotedString(const CString& str, CString& output)
|
||||
{
|
||||
CString product;
|
||||
const char *value = str.c_str();
|
||||
// fast mode
|
||||
bool isFast = IsFastValueToQuotedString(value);
|
||||
output += "\"";
|
||||
bool isFast = IsFastValueToQuotedString(str); // fast mode
|
||||
if (isFast) {
|
||||
product += "\"";
|
||||
product += str;
|
||||
product += "\"";
|
||||
return product;
|
||||
output += str;
|
||||
output += "\"";
|
||||
return;
|
||||
}
|
||||
// 1. Let product be code unit 0x0022 (QUOTATION MARK).
|
||||
product += "\"";
|
||||
// 2. For each code unit C in value
|
||||
for (const char *c = value; *c != 0; ++c) {
|
||||
switch (*c) {
|
||||
/*
|
||||
* a. If C is 0x0022 (QUOTATION MARK) or 0x005C (REVERSE SOLIDUS), then
|
||||
* i. Let product be the concatenation of product and code unit 0x005C (REVERSE SOLIDUS).
|
||||
* ii. Let product be the concatenation of product and C.
|
||||
*/
|
||||
for (uint32_t i = 0; i < str.size(); ++i) {
|
||||
auto ch = str[i];
|
||||
switch (ch) {
|
||||
case '\"':
|
||||
product += "\\\"";
|
||||
output += "\\\"";
|
||||
break;
|
||||
case '\\':
|
||||
product += "\\\\";
|
||||
output += "\\\\";
|
||||
break;
|
||||
/*
|
||||
* b. Else if C is 0x0008 (BACKSPACE), 0x000C (FORM FEED), 0x000A (LINE FEED), 0x000D (CARRIAGE RETURN),
|
||||
* or 0x000B (LINE TABULATION), then
|
||||
* i. Let product be the concatenation of product and code unit 0x005C (REVERSE SOLIDUS).
|
||||
* ii. Let abbrev be the String value corresponding to the value of C as follows:
|
||||
* BACKSPACE "b"
|
||||
* FORM FEED (FF) "f"
|
||||
* LINE FEED (LF) "n"
|
||||
* CARRIAGE RETURN (CR) "r"
|
||||
* LINE TABULATION "t"
|
||||
* iii. Let product be the concatenation of product and abbrev.
|
||||
*/
|
||||
case '\b':
|
||||
product += "\\b";
|
||||
output += "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
product += "\\f";
|
||||
output += "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
product += "\\n";
|
||||
output += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
product += "\\r";
|
||||
output += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
product += "\\t";
|
||||
output += "\\t";
|
||||
break;
|
||||
case ZERO_FIRST:
|
||||
product += "\\u0000";
|
||||
++c;
|
||||
output += "\\u0000";
|
||||
++i;
|
||||
break;
|
||||
case ALONE_SURROGATE_3B_FIRST:
|
||||
if (*(c + 1) && *(c + 1) >= ALONE_SURROGATE_3B_SECOND_START &&
|
||||
*(c + 1) <= ALONE_SURROGATE_3B_SECOND_END &&
|
||||
*(c + 2) >= ALONE_SURROGATE_3B_THIRD_START && // 2 : The third character after c
|
||||
*(c + 2) <= ALONE_SURROGATE_3B_THIRD_END) { // 2 : The third character after c
|
||||
auto unicodeRes = utf_helper::ConvertUtf8ToUnicodeChar((uint8_t *)c, 3);
|
||||
std::ostringstream oss;
|
||||
oss << "\\u" << std::hex << std::setfill('0') << std::setw(FOUR_HEX) <<
|
||||
static_cast<int>(unicodeRes.first);
|
||||
product += oss.str();
|
||||
c += 2; // 2 : Skip 2 characters
|
||||
if (i + 2 < str.size() && // 2: Check 2 more characters
|
||||
str[i + 1] >= ALONE_SURROGATE_3B_SECOND_START && // 1: The first character after ch
|
||||
str[i + 1] <= ALONE_SURROGATE_3B_SECOND_END && // 1: The first character after ch
|
||||
str[i + 2] >= ALONE_SURROGATE_3B_THIRD_START && // 2: The second character after ch
|
||||
str[i + 2] <= ALONE_SURROGATE_3B_THIRD_END) { // 2: The second character after ch
|
||||
auto unicodeRes = utf_helper::ConvertUtf8ToUnicodeChar(
|
||||
reinterpret_cast<const uint8_t*>(str.c_str() + i), 3); // 3: Parse 3 characters
|
||||
AppendUnicodeEscape(static_cast<int>(unicodeRes.first), output);
|
||||
i += 2; // 2 : Skip 2 characters
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
// c. Else if C has a code unit value less than 0x0020 (SPACE), then
|
||||
if (*c > 0 && *c < CODE_SPACE) {
|
||||
/*
|
||||
* i. Let product be the concatenation of product and code unit 0x005C (REVERSE SOLIDUS).
|
||||
* ii. Let product be the concatenation of product and "u".
|
||||
* iii. Let hex be the string result of converting the numeric code unit value of C to a String of
|
||||
* four hexadecimal digits. Alphabetic hexadecimal digits are presented as lowercase Latin letters.
|
||||
* iv. Let product be the concatenation of product and hex.
|
||||
*/
|
||||
std::ostringstream oss;
|
||||
oss << "\\u" << std::hex << std::setfill('0') << std::setw(FOUR_HEX) << static_cast<int>(*c);
|
||||
product += oss.str();
|
||||
if (ch > 0 && ch < CODE_SPACE) {
|
||||
AppendUnicodeEscape(static_cast<int>(ch), output);
|
||||
} else {
|
||||
// Else,
|
||||
// i. Let product be the concatenation of product and C.
|
||||
product += *c;
|
||||
output += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. Let product be the concatenation of product and code unit 0x0022 (QUOTATION MARK).
|
||||
product += "\"";
|
||||
// Return product.
|
||||
return product;
|
||||
output += "\"";
|
||||
}
|
||||
} // namespace panda::ecmascript::base
|
@ -21,6 +21,10 @@
|
||||
#include "ecmascript/property_attributes.h"
|
||||
|
||||
namespace panda::ecmascript::base {
|
||||
constexpr int HEX_DIGIT_MASK = 0xF;
|
||||
constexpr int HEX_SHIFT_THREE = 12;
|
||||
constexpr int HEX_SHIFT_TWO = 8;
|
||||
constexpr int HEX_SHIFT_ONE = 4;
|
||||
|
||||
class JsonHelper {
|
||||
public:
|
||||
@ -58,9 +62,18 @@ public:
|
||||
return type == TransformType::SENDABLE || type == TransformType::BIGINT;
|
||||
}
|
||||
|
||||
static CString ValueToQuotedString(CString str);
|
||||
static inline void AppendUnicodeEscape(int ch, CString& output)
|
||||
{
|
||||
static constexpr char HEX_DIGIT[] = "0123456789abcdef";
|
||||
output += "\\u";
|
||||
output += HEX_DIGIT[(ch >> HEX_SHIFT_THREE) & HEX_DIGIT_MASK];
|
||||
output += HEX_DIGIT[(ch >> HEX_SHIFT_TWO) & HEX_DIGIT_MASK];
|
||||
output += HEX_DIGIT[(ch >> HEX_SHIFT_ONE) & HEX_DIGIT_MASK];
|
||||
output += HEX_DIGIT[ch & HEX_DIGIT_MASK];
|
||||
}
|
||||
|
||||
static bool IsFastValueToQuotedString(const char *value);
|
||||
static bool IsFastValueToQuotedString(const CString& str);
|
||||
static void AppendValueToQuotedString(const CString& str, CString& output);
|
||||
|
||||
static inline bool CompareKey(const std::pair<JSHandle<JSTaggedValue>, PropertyAttributes> &a,
|
||||
const std::pair<JSHandle<JSTaggedValue>, PropertyAttributes> &b)
|
||||
|
@ -163,9 +163,7 @@ bool JsonStringifier::CalculateNumberGap(JSTaggedValue gap)
|
||||
int num = static_cast<int>(numValue);
|
||||
if (num > 0) {
|
||||
int gapLength = std::min(num, GAP_MAX_LEN);
|
||||
for (int i = 0; i < gapLength; i++) {
|
||||
gap_ += " ";
|
||||
}
|
||||
gap_.append(gapLength, ' ');
|
||||
gap_.append("\0");
|
||||
}
|
||||
return true;
|
||||
@ -184,8 +182,7 @@ bool JsonStringifier::CalculateStringGap(const JSHandle<EcmaString> &primString)
|
||||
gapLength = GAP_MAX_LEN;
|
||||
}
|
||||
}
|
||||
CString str = gapString.substr(0, gapLength);
|
||||
gap_ += str;
|
||||
gap_.append(gapString.c_str(), gapLength);
|
||||
gap_.append("\0");
|
||||
}
|
||||
return true;
|
||||
@ -318,8 +315,7 @@ JSTaggedValue JsonStringifier::SerializeJSONProperty(const JSHandle<JSTaggedValu
|
||||
auto string = JSHandle<EcmaString>(thread_,
|
||||
EcmaStringAccessor::Flatten(thread_->GetEcmaVM(), strHandle));
|
||||
CString str = ConvertToString(*string, StringConvertedUsage::LOGICOPERATION);
|
||||
str = JsonHelper::ValueToQuotedString(str);
|
||||
result_ += str;
|
||||
JsonHelper::AppendValueToQuotedString(str, result_);
|
||||
return tagValue;
|
||||
}
|
||||
case JSType::JS_PRIMITIVE_REF: {
|
||||
@ -385,8 +381,7 @@ void JsonStringifier::SerializeObjectKey(const JSHandle<JSTaggedValue> &key, boo
|
||||
str = ConvertToString(*JSTaggedValue::ToString(thread_, key), StringConvertedUsage::LOGICOPERATION);
|
||||
}
|
||||
result_ += stepBegin;
|
||||
str = JsonHelper::ValueToQuotedString(str);
|
||||
result_ += str;
|
||||
JsonHelper::AppendValueToQuotedString(str, result_);
|
||||
result_ += ":";
|
||||
result_ += stepEnd;
|
||||
}
|
||||
@ -609,8 +604,7 @@ void JsonStringifier::SerializePrimitiveRef(const JSHandle<JSTaggedValue> &primi
|
||||
auto priStr = JSTaggedValue::ToString(thread_, primitiveRef);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread_);
|
||||
CString str = ConvertToString(*priStr, StringConvertedUsage::LOGICOPERATION);
|
||||
str = JsonHelper::ValueToQuotedString(str);
|
||||
result_ += str;
|
||||
JsonHelper::AppendValueToQuotedString(str, result_);
|
||||
} else if (primitive.IsNumber()) {
|
||||
auto priNum = JSTaggedValue::ToNumber(thread_, primitiveRef);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread_);
|
||||
|
@ -40,10 +40,6 @@ public:
|
||||
const JSHandle<JSTaggedValue> &gap);
|
||||
|
||||
private:
|
||||
CString ValueToQuotedString(CString str);
|
||||
|
||||
bool IsFastValueToQuotedString(const char *value);
|
||||
|
||||
void AddDeduplicateProp(const JSHandle<JSTaggedValue> &property);
|
||||
|
||||
JSTaggedValue SerializeJSONProperty(const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &replacer);
|
||||
|
Loading…
Reference in New Issue
Block a user