Optimize JSON Quote operation. (#2420)

JerryScript-DCO-1.0-Signed-off-by: Anthony Calandra anthony@anthony-calandra.com
This commit is contained in:
Anthony Calandra 2018-07-10 09:00:19 -04:00 committed by Zoltan Herczeg
parent 0c6b5eae65
commit 50daa39ee8
3 changed files with 93 additions and 67 deletions

View File

@ -1213,107 +1213,137 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */
static ecma_value_t
ecma_builtin_json_quote (ecma_string_t *string_p) /**< string that should be quoted*/
{
/* 1. */
ecma_string_t *product_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR);
ECMA_STRING_TO_UTF8_STRING (string_p, string_buff, string_buff_size);
const lit_utf8_byte_t *str_p = string_buff;
const lit_utf8_byte_t *str_end_p = string_buff + string_buff_size;
const lit_utf8_byte_t *str_end_p = str_p + string_buff_size;
size_t n_bytes = 2; /* Start with 2 for surrounding quotes. */
while (str_p < str_end_p)
{
ecma_char_t current_char = lit_utf8_read_next (&str_p);
lit_utf8_byte_t c = *str_p++;
/* 2.a, b */
if (current_char == LIT_CHAR_BACKSLASH
|| current_char == LIT_CHAR_DOUBLE_QUOTE
|| current_char == LIT_CHAR_BS
|| current_char == LIT_CHAR_FF
|| current_char == LIT_CHAR_LF
|| current_char == LIT_CHAR_CR
|| current_char == LIT_CHAR_TAB)
if (c == LIT_CHAR_BACKSLASH || c == LIT_CHAR_DOUBLE_QUOTE)
{
lit_utf8_byte_t abbrev = (lit_utf8_byte_t) current_char;
n_bytes += 2;
}
else if (c >= LIT_CHAR_SP && c < LIT_UTF8_1_BYTE_CODE_POINT_MAX)
{
n_bytes++;
}
else if (c > LIT_UTF8_1_BYTE_CODE_POINT_MAX)
{
lit_utf8_size_t sz = lit_get_unicode_char_size_by_utf8_first_byte (c);
n_bytes += sz;
str_p += sz - 1;
}
else
{
switch (c)
{
case LIT_CHAR_BS:
case LIT_CHAR_FF:
case LIT_CHAR_LF:
case LIT_CHAR_CR:
case LIT_CHAR_TAB:
{
n_bytes += 2;
break;
}
default: /* Hexadecimal. */
{
n_bytes += 2 + 4;
break;
}
}
}
}
switch (current_char)
lit_utf8_byte_t *buf_begin = jmem_heap_alloc_block (n_bytes);
JERRY_ASSERT (buf_begin != NULL);
lit_utf8_byte_t *buf = buf_begin;
str_p = string_buff;
*buf++ = LIT_CHAR_DOUBLE_QUOTE;
while (str_p < str_end_p)
{
lit_utf8_byte_t c = *str_p++;
if (c == LIT_CHAR_BACKSLASH || c == LIT_CHAR_DOUBLE_QUOTE)
{
*buf++ = LIT_CHAR_BACKSLASH;
*buf++ = c;
}
else if (c >= LIT_CHAR_SP && c < LIT_UTF8_1_BYTE_CODE_POINT_MAX)
{
*buf++ = c;
}
else if (c > LIT_UTF8_1_BYTE_CODE_POINT_MAX)
{
str_p--;
ecma_char_t current_char = lit_utf8_read_next (&str_p);
buf += lit_code_unit_to_utf8 (current_char, (lit_utf8_byte_t *) buf);
}
else
{
switch (c)
{
case LIT_CHAR_BS:
{
abbrev = LIT_CHAR_LOWERCASE_B;
*buf++ = LIT_CHAR_BACKSLASH;
*buf++ = LIT_CHAR_LOWERCASE_B;
break;
}
case LIT_CHAR_FF:
{
abbrev = LIT_CHAR_LOWERCASE_F;
*buf++ = LIT_CHAR_BACKSLASH;
*buf++ = LIT_CHAR_LOWERCASE_F;
break;
}
case LIT_CHAR_LF:
{
abbrev = LIT_CHAR_LOWERCASE_N;
*buf++ = LIT_CHAR_BACKSLASH;
*buf++ = LIT_CHAR_LOWERCASE_N;
break;
}
case LIT_CHAR_CR:
{
abbrev = LIT_CHAR_LOWERCASE_R;
*buf++ = LIT_CHAR_BACKSLASH;
*buf++ = LIT_CHAR_LOWERCASE_R;
break;
}
case LIT_CHAR_TAB:
{
abbrev = LIT_CHAR_LOWERCASE_T;
*buf++ = LIT_CHAR_BACKSLASH;
*buf++ = LIT_CHAR_LOWERCASE_T;
break;
}
default:
default: /* Hexadecimal. */
{
JERRY_ASSERT (current_char == LIT_CHAR_BACKSLASH || current_char == LIT_CHAR_DOUBLE_QUOTE);
JERRY_ASSERT (c < 0x9f);
*buf++ = LIT_CHAR_BACKSLASH;
*buf++ = LIT_CHAR_LOWERCASE_U;
*buf++ = LIT_CHAR_0;
*buf++ = LIT_CHAR_0;
*buf++ = (lit_utf8_byte_t) (LIT_CHAR_0 + (c >> 4)); /* Max range 0-9, hex digits unnecessary. */
lit_utf8_byte_t c2 = (c & 0xf);
*buf++ = (lit_utf8_byte_t) (c2 + ((c2 <= 9) ? LIT_CHAR_0 : (LIT_CHAR_LOWERCASE_A - 10)));
break;
}
}
lit_utf8_byte_t chars[2] = { LIT_CHAR_BACKSLASH, abbrev };
product_str_p = ecma_append_chars_to_string (product_str_p, chars, 2, 2);
}
/* 2.c */
else if (current_char < LIT_CHAR_SP)
{
lit_utf8_byte_t chars[6] = { LIT_CHAR_BACKSLASH, LIT_CHAR_LOWERCASE_U, LIT_CHAR_0, LIT_CHAR_0 };
JERRY_ASSERT (current_char < 0x9f);
chars[4] = (lit_utf8_byte_t) (LIT_CHAR_0 + (current_char >> 4));
int last_char = current_char & 0xf;
last_char += (last_char <= 9) ? LIT_CHAR_0 : (LIT_CHAR_LOWERCASE_A - 10);
chars[5] = (lit_utf8_byte_t) last_char;
product_str_p = ecma_append_chars_to_string (product_str_p, chars, 6, 6);
}
/* 2.d */
else if (current_char < LIT_UTF8_1_BYTE_CODE_POINT_MAX)
{
/* Fast case for ascii characters. */
lit_utf8_byte_t chars[1] = { (lit_utf8_byte_t) current_char };
product_str_p = ecma_append_chars_to_string (product_str_p, chars, 1, 1);
}
else
{
ecma_string_t *current_char_str_p = ecma_new_ecma_string_from_code_unit (current_char);
product_str_p = ecma_concat_ecma_strings (product_str_p, current_char_str_p);
ecma_deref_ecma_string (current_char_str_p);
}
}
*buf++ = LIT_CHAR_DOUBLE_QUOTE;
/* Make sure we didn't run off the end or allocated more than we actually wanted. */
JERRY_ASSERT ((size_t) (buf - buf_begin) == n_bytes);
ecma_string_t *product_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) buf_begin,
(lit_utf8_size_t) (buf - buf_begin));
jmem_heap_free_block (buf_begin, n_bytes);
ECMA_FINALIZE_UTF8_STRING (string_buff, string_buff_size);
/* 3. */
product_str_p = ecma_append_magic_string_to_string (product_str_p, LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR);
/* 4. */
return ecma_make_string_value (product_str_p);
} /* ecma_builtin_json_quote */

View File

@ -19,9 +19,6 @@
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING__EMPTY, "")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPACE_CHAR, " ")
#if !defined (CONFIG_DISABLE_JSON_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR, "\"")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMMA_CHAR, ",")
#if !defined (CONFIG_DISABLE_REGEXP_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SLASH_CHAR, "/")

View File

@ -24,7 +24,6 @@
LIT_MAGIC_STRING__EMPTY = ""
LIT_MAGIC_STRING_SPACE_CHAR = " "
LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR = "\""
LIT_MAGIC_STRING_COMMA_CHAR = ","
LIT_MAGIC_STRING_SLASH_CHAR = "/"
LIT_MAGIC_STRING_COLON_CHAR = ":"