/** * Get the contents of the literal as a zero-terminated string. * If literal is a magic string record, the corresponding string is not copied to the buffer, * but is returned directly. * * @return pointer to the zero-terminated string. */ const lit_utf8_byte_t * lit_literal_to_utf8_string (literal_t lit, /**< literal to be processed */ lit_utf8_byte_t *buff_p, /**< buffer to use as a string storage */ size_t size) /**< size of the buffer */ { JERRY_ASSERT (buff_p != NULL && size > 0); rcs_record_t::type_t type = lit->get_type (); switch (type) { case LIT_STR_T: { lit_charset_record_t *ch_rec_p = static_cast<lit_charset_record_t *> (lit); ch_rec_p->get_charset (buff_p, size); return buff_p; } case LIT_MAGIC_STR_T: { return lit_get_magic_string_utf8 (lit_magic_record_get_magic_str_id (lit)); } case LIT_MAGIC_STR_EX_T: { return lit_get_magic_string_ex_utf8 (lit_magic_record_ex_get_magic_str_id (lit)); } case LIT_NUMBER_T: { ecma_number_to_utf8_string (static_cast<lit_number_record_t *> (lit)->get_number (), buff_p, (ssize_t)size); return buff_p; } default: JERRY_UNREACHABLE (); } JERRY_UNREACHABLE (); } /* lit_literal_to_utf8_string */
/** * Debug utility to print a number. */ static void util_print_number (ecma_number_t num_p) /**< number to print */ { lit_utf8_byte_t str_buf[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t str_size = ecma_number_to_utf8_string (num_p, str_buf, sizeof (str_buf)); str_buf[str_size] = 0; printf ("%s", str_buf); } /* util_print_number */
/** * Get size of container heap number of ecma-string * * Note: the number size and length are equal * * @return number of bytes in the buffer */ static inline lit_utf8_size_t __attr_always_inline___ ecma_string_get_heap_number_size (jmem_cpointer_t number_cp) /**< Compressed pointer to an ecma_number_t */ { const ecma_number_t *num_p = ECMA_GET_NON_NULL_POINTER (ecma_number_t, number_cp); lit_utf8_byte_t buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; return ecma_number_to_utf8_string (*num_p, buffer, sizeof (buffer)); } /* ecma_string_get_heap_number_size */
/** * Check if literal contains the string equal to the passed number * * @return true if equal * false otherwise */ bool lit_literal_equal_num (lit_literal_t lit, /**< literal to check */ ecma_number_t num) /**< number to compare with */ { lit_utf8_byte_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t copied = ecma_number_to_utf8_string (num, buff, sizeof (buff)); return lit_literal_equal_utf8 (lit, buff, copied); } /* lit_literal_equal_num */
/** * Allocate new ecma-string and fill it with ecma-number * * @return pointer to ecma-string descriptor */ ecma_string_t * ecma_new_ecma_string_from_number (ecma_number_t num) /**< ecma-number */ { uint32_t uint32_num = ecma_number_to_uint32 (num); if (num == ((ecma_number_t) uint32_num)) { return ecma_new_ecma_string_from_uint32 (uint32_num); } if (ecma_number_is_nan (num)) { return ecma_get_magic_string (LIT_MAGIC_STRING_NAN); } if (ecma_number_is_infinity (num)) { lit_magic_string_id_t id = (ecma_number_is_negative (num) ? LIT_MAGIC_STRING_NEGATIVE_INFINITY_UL : LIT_MAGIC_STRING_INFINITY_UL); return ecma_get_magic_string (id); } lit_utf8_byte_t str_buf[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t str_size = ecma_number_to_utf8_string (num, str_buf, sizeof (str_buf)); JERRY_ASSERT (str_size > 0); #ifndef JERRY_NDEBUG lit_magic_string_id_t magic_string_id; lit_magic_string_ex_id_t magic_string_ex_id; JERRY_ASSERT (!lit_is_utf8_string_magic (str_buf, str_size, &magic_string_id) && !lit_is_ex_utf8_string_magic (str_buf, str_size, &magic_string_ex_id)); #endif /* !JERRY_NDEBUG */ ecma_string_t *string_desc_p = jmem_heap_alloc_block (sizeof (ecma_string_t) + str_size); string_desc_p->refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE; string_desc_p->hash = lit_utf8_string_calc_hash (str_buf, str_size); string_desc_p->u.common_field = 0; string_desc_p->u.utf8_string.size = (uint16_t) str_size; string_desc_p->u.utf8_string.length = (uint16_t) str_size; lit_utf8_byte_t *data_p = (lit_utf8_byte_t *) (string_desc_p + 1); memcpy (data_p, str_buf, str_size); return string_desc_p; } /* ecma_new_ecma_string_from_number */
/** * Check if literal equals to charset record * * @return true if is_equal * false otherwise */ static bool lit_literal_equal_charset_rec (lit_literal_t lit, /**< literal to compare */ lit_literal_t record) /**< charset record to compare */ { switch (lit->type) { case LIT_RECORD_TYPE_CHARSET: { return lit_literal_equal_charset (lit, lit_charset_literal_get_charset (record), lit_charset_literal_get_size (record)); } case LIT_RECORD_TYPE_MAGIC_STR: { lit_magic_string_id_t magic_string_id = lit_magic_literal_get_magic_str_id (lit); return lit_literal_equal_charset (record, lit_get_magic_string_utf8 (magic_string_id), lit_get_magic_string_size (magic_string_id)); } case LIT_RECORD_TYPE_MAGIC_STR_EX: { lit_magic_string_ex_id_t magic_string_id = lit_magic_literal_get_magic_str_ex_id (lit); return lit_literal_equal_charset (record, lit_get_magic_string_ex_utf8 (magic_string_id), lit_get_magic_string_ex_size (magic_string_id)); } case LIT_RECORD_TYPE_NUMBER: { ecma_number_t num = lit_number_literal_get_number (lit); lit_utf8_byte_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t copied = ecma_number_to_utf8_string (num, buff, sizeof (buff)); return lit_literal_equal_charset (record, buff, copied); } default: { JERRY_UNREACHABLE (); return false; } } } /* lit_literal_equal_charset_rec */
/** * Check if literal equals to utf-8 string * * @return true if equal * false otherwise */ bool lit_literal_equal_utf8 (lit_literal_t lit, /**< literal to compare */ const lit_utf8_byte_t *str_p, /**< utf-8 string to compare */ lit_utf8_size_t str_size) /**< string size in bytes */ { switch (lit->type) { case LIT_RECORD_TYPE_CHARSET: { if (lit_charset_literal_get_size (lit) != str_size) { return 0; } return !strncmp ((const char *) lit_charset_literal_get_charset (lit), (const char *) str_p, str_size); } case LIT_RECORD_TYPE_MAGIC_STR: { lit_magic_string_id_t magic_id = lit_magic_literal_get_magic_str_id (lit); return lit_compare_utf8_string_and_magic_string (str_p, str_size, magic_id); } case LIT_RECORD_TYPE_MAGIC_STR_EX: { lit_magic_string_ex_id_t magic_id = lit_magic_literal_get_magic_str_ex_id (lit); return lit_compare_utf8_string_and_magic_string_ex (str_p, str_size, magic_id); } case LIT_RECORD_TYPE_NUMBER: { ecma_number_t num = lit_number_literal_get_number (lit); lit_utf8_byte_t num_buf[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t num_size = ecma_number_to_utf8_string (num, num_buf, sizeof (num_buf)); return lit_compare_utf8_strings (str_p, str_size, num_buf, num_size); } default: { JERRY_UNREACHABLE (); } } } /* lit_literal_equal_utf8 */
/** * Check if literal equals to charset record * * @return true if is_equal * false otherwise */ static bool lit_literal_equal_charset_rec (literal_t lit, /**< literal to compare */ lit_charset_record_t *record) /**< charset record to compare */ { switch (lit->get_type ()) { case LIT_STR_T: { return static_cast<lit_charset_record_t *>(lit)->is_equal (record); } case LIT_MAGIC_STR_T: { lit_magic_string_id_t magic_string_id = lit_magic_record_get_magic_str_id (lit); return record->is_equal_utf8_string (lit_get_magic_string_utf8 (magic_string_id), lit_get_magic_string_size (magic_string_id)); } case LIT_MAGIC_STR_EX_T: { lit_magic_string_ex_id_t magic_string_id = lit_magic_record_ex_get_magic_str_id (lit); return record->is_equal_utf8_string (lit_get_magic_string_ex_utf8 (magic_string_id), lit_get_magic_string_ex_size (magic_string_id)); } case LIT_NUMBER_T: { lit_utf8_byte_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t copied = ecma_number_to_utf8_string (static_cast<lit_number_record_t *>(lit)->get_number (), buff, sizeof (buff)); return record->is_equal_utf8_string (buff, copied); } default: { JERRY_UNREACHABLE (); } } } /* lit_literal_equal_charset_rec */
/** * Check if literal equals to utf-8 string * * @return true if equal * false otherwise */ bool lit_literal_equal_utf8 (literal_t lit, /**< literal to compare */ const lit_utf8_byte_t *str_p, /**< utf-8 string to compare */ lit_utf8_size_t str_size) /**< string size in bytes */ { switch (lit->get_type ()) { case LIT_STR_T: { return static_cast<lit_charset_record_t *>(lit)->is_equal_utf8_string (str_p, str_size); } case LIT_MAGIC_STR_T: { lit_magic_string_id_t magic_id = lit_magic_record_get_magic_str_id (lit); return lit_compare_utf8_string_and_magic_string (str_p, str_size, magic_id); } case LIT_MAGIC_STR_EX_T: { lit_magic_string_ex_id_t magic_id = lit_magic_record_ex_get_magic_str_id (lit); return lit_compare_utf8_string_and_magic_string_ex (str_p, str_size, magic_id); } case LIT_NUMBER_T: { lit_utf8_byte_t num_buf[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t num_size = ecma_number_to_utf8_string (static_cast<lit_number_record_t *>(lit)->get_number (), num_buf, sizeof (num_buf)); return lit_compare_utf8_strings (str_p, str_size, num_buf, num_size); } default: { JERRY_UNREACHABLE (); } } } /* lit_literal_equal_utf8 */
int main (int __attr_unused___ argc, char __attr_unused___ **argv) { TEST_INIT (); const lit_utf8_byte_t *ptrs[test_sub_iters]; ecma_number_t numbers[test_sub_iters]; lit_utf8_byte_t strings[test_sub_iters][max_characters_in_string + 1]; lit_utf8_size_t lengths[test_sub_iters]; jmem_init (); lit_init (); for (uint32_t i = 0; i < test_iters; i++) { memset (numbers, 0, sizeof (ecma_number_t) * test_sub_iters); memset (lengths, 0, sizeof (lit_utf8_size_t) * test_sub_iters); memset (ptrs, 0, sizeof (lit_utf8_byte_t *) * test_sub_iters); for (uint32_t j = 0; j < test_sub_iters; j++) { int type = rand () % 3; if (type == 0) { lengths[j] = (lit_utf8_size_t) (rand () % max_characters_in_string + 1); generate_string (strings[j], lengths[j]); lit_create_literal_from_utf8_string (strings[j], lengths[j]); strings[j][lengths[j]] = '\0'; ptrs[j] = strings[j]; JERRY_ASSERT (ptrs[j]); } else if (type == 1) { lit_magic_string_id_t msi = (lit_magic_string_id_t) (rand () % LIT_MAGIC_STRING__COUNT); ptrs[j] = lit_get_magic_string_utf8 (msi); JERRY_ASSERT (ptrs[j]); lengths[j] = (lit_utf8_size_t) lit_zt_utf8_string_size (ptrs[j]); lit_create_literal_from_utf8_string (ptrs[j], lengths[j]); } else { ecma_number_t num = generate_number (); lengths[j] = ecma_number_to_utf8_string (num, strings[j], max_characters_in_string); lit_create_literal_from_num (num); } } // Add empty string lit_create_literal_from_utf8_string (NULL, 0); for (uint32_t j = 0; j < test_sub_iters; j++) { lit_literal_t lit1; lit_literal_t lit2; if (ptrs[j]) { lit1 = lit_find_or_create_literal_from_utf8_string (ptrs[j], lengths[j]); lit2 = lit_find_literal_by_utf8_string (ptrs[j], lengths[j]); JERRY_ASSERT (compare_utf8_string_and_string_literal (ptrs[j], lengths[j], lit1)); JERRY_ASSERT (compare_utf8_string_and_string_literal (ptrs[j], lengths[j], lit2)); } else { lit1 = lit_find_or_create_literal_from_num (numbers[j]); lit2 = lit_find_literal_by_num (numbers[j]); JERRY_ASSERT (numbers[j] == lit_number_literal_get_number (lit1)); JERRY_ASSERT (numbers[j] == lit_number_literal_get_number (lit2)); } JERRY_ASSERT (lit1); JERRY_ASSERT (lit2); JERRY_ASSERT (lit1 == lit2); } // Check empty string exists JERRY_ASSERT (lit_find_literal_by_utf8_string (NULL, 0)); } lit_finalize (); jmem_finalize (true); return 0; } /* main */
/** * Dump the contents of the literal storage. */ void lit_dump_literals () { lit_record_t *rec_p; size_t i; JERRY_DLOG ("LITERALS:\n"); for (rec_p = lit_storage; rec_p != NULL; rec_p = lit_cpointer_decompress (rec_p->next)) { JERRY_DLOG ("%p ", rec_p); JERRY_DLOG ("[%3zu] ", lit_get_literal_size (rec_p)); switch (rec_p->type) { case LIT_RECORD_TYPE_CHARSET: { const lit_charset_record_t *const record_p = (const lit_charset_record_t *) rec_p; char *str = (char *) (record_p + 1); for (i = 0; i < record_p->size; ++i, ++str) { /* TODO: Support proper printing of characters which occupy more than one byte. */ JERRY_DLOG ("%c", *str); } JERRY_DLOG (" : STRING"); break; } case LIT_RECORD_TYPE_MAGIC_STR: { lit_magic_string_id_t id = (lit_magic_string_id_t) ((lit_magic_record_t *) rec_p)->magic_id; JERRY_DLOG ("%s : MAGIC STRING", lit_get_magic_string_utf8 (id)); JERRY_DLOG (" [id=%d] ", id); break; } case LIT_RECORD_TYPE_MAGIC_STR_EX: { lit_magic_string_ex_id_t id = ((lit_magic_record_t *) rec_p)->magic_id; JERRY_DLOG ("%s : EXT MAGIC STRING", lit_get_magic_string_ex_utf8 (id)); JERRY_DLOG (" [id=%d] ", id); break; } case LIT_RECORD_TYPE_NUMBER: { const lit_number_record_t *const record_p = (const lit_number_record_t *) rec_p; ecma_number_t value; memcpy (&value, &record_p->number, sizeof (ecma_number_t)); if (ecma_number_is_nan (value)) { JERRY_DLOG ("%s : NUMBER", "NaN"); } else { lit_utf8_byte_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER + 1u]; memset (buff, 0, sizeof (buff)); lit_utf8_size_t sz = ecma_number_to_utf8_string (value, buff, sizeof (buff)); JERRY_ASSERT (sz <= ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER); JERRY_DLOG ("%s : NUMBER", buff); } break; } default: { JERRY_UNREACHABLE (); } } JERRY_DLOG ("\n"); } } /* lit_dump_literals */
int main (void) { TEST_INIT (); const lit_utf8_byte_t *ptrs[test_sub_iters]; ecma_number_t numbers[test_sub_iters]; lit_utf8_byte_t strings[test_sub_iters][max_characters_in_string + 1]; lit_utf8_size_t lengths[test_sub_iters]; jmem_init (); for (uint32_t i = 0; i < test_iters; i++) { memset (numbers, 0, sizeof (ecma_number_t) * test_sub_iters); memset (lengths, 0, sizeof (lit_utf8_size_t) * test_sub_iters); memset (ptrs, 0, sizeof (lit_utf8_byte_t *) * test_sub_iters); for (uint32_t j = 0; j < test_sub_iters; j++) { int type = rand () % 3; if (type == 0) { lengths[j] = (lit_utf8_size_t) (rand () % max_characters_in_string + 1); generate_string (strings[j], lengths[j]); ecma_find_or_create_literal_string (strings[j], lengths[j]); strings[j][lengths[j]] = '\0'; ptrs[j] = strings[j]; TEST_ASSERT (ptrs[j]); } else if (type == 1) { lit_magic_string_id_t msi = (lit_magic_string_id_t) (rand () % LIT_NON_INTERNAL_MAGIC_STRING__COUNT); ptrs[j] = lit_get_magic_string_utf8 (msi); TEST_ASSERT (ptrs[j]); lengths[j] = (lit_utf8_size_t) lit_zt_utf8_string_size (ptrs[j]); ecma_find_or_create_literal_string (ptrs[j], lengths[j]); } else { ecma_number_t num = generate_number (); lengths[j] = ecma_number_to_utf8_string (num, strings[j], max_characters_in_string); ecma_find_or_create_literal_number (num); } } /* Add empty string. */ ecma_find_or_create_literal_string (NULL, 0); for (uint32_t j = 0; j < test_sub_iters; j++) { jmem_cpointer_t lit1; jmem_cpointer_t lit2; if (ptrs[j]) { lit1 = ecma_find_or_create_literal_string (ptrs[j], lengths[j]); lit2 = ecma_find_or_create_literal_string (ptrs[j], lengths[j]); TEST_ASSERT (lit1 == lit2); } else { lit1 = ecma_find_or_create_literal_number (numbers[j]); lit2 = ecma_find_or_create_literal_number (numbers[j]); TEST_ASSERT (lit1 == lit2); } TEST_ASSERT (lit1); TEST_ASSERT (lit2); TEST_ASSERT (lit1 == lit2); } /* Check empty string exists. */ TEST_ASSERT (ecma_find_or_create_literal_string (NULL, 0) != JMEM_CP_NULL); } ecma_finalize_lit_storage (); jmem_finalize (); return 0; } /* main */