/** * Check if two literals are equal * * @return true if equal * false otherwise */ bool lit_literal_equal (literal_t lit1, /**< first literal */ literal_t lit2) /**< second literal */ { switch (lit2->get_type ()) { case lit_literal_storage_t::LIT_STR: { return lit_literal_equal_charset_rec (lit1, static_cast<lit_charset_record_t *>(lit2)); } case lit_literal_storage_t::LIT_MAGIC_STR: { lit_magic_string_id_t magic_str_id = lit_magic_record_get_magic_str_id (lit2); return lit_literal_equal_utf8 (lit1, lit_get_magic_string_utf8 (magic_str_id), lit_get_magic_string_size (magic_str_id)); } case lit_literal_storage_t::LIT_MAGIC_STR_EX: { lit_magic_string_ex_id_t magic_str_ex_id = lit_magic_record_ex_get_magic_str_id (lit2); return lit_literal_equal_utf8 (lit1, lit_get_magic_string_ex_utf8 (magic_str_ex_id), lit_get_magic_string_ex_size (magic_str_ex_id)); } case lit_literal_storage_t::LIT_NUMBER: { return lit_literal_equal_num (lit1, static_cast<lit_number_record_t *>(lit2)->get_number ()); } default: { JERRY_UNREACHABLE (); } } } /* lit_literal_equal */
/** * Register external magic strings */ void lit_magic_strings_ex_set (const lit_utf8_byte_t **ex_str_items, /**< character arrays, representing * external magic strings' contents */ uint32_t count, /**< number of the strings */ const lit_utf8_size_t *ex_str_sizes) /**< sizes of the strings */ { JERRY_ASSERT (ex_str_items != NULL); JERRY_ASSERT (count > 0); JERRY_ASSERT (ex_str_sizes != NULL); JERRY_ASSERT (lit_magic_string_ex_array == NULL); JERRY_ASSERT (lit_magic_string_ex_count == 0); JERRY_ASSERT (lit_magic_string_ex_sizes == NULL); /* Set external magic strings information */ lit_magic_string_ex_array = ex_str_items; lit_magic_string_ex_count = count; lit_magic_string_ex_sizes = ex_str_sizes; #ifndef JERRY_NDEBUG for (lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) 0; id < lit_magic_string_ex_count; id = (lit_magic_string_ex_id_t) (id + 1)) { JERRY_ASSERT (lit_magic_string_ex_sizes[id] == lit_zt_utf8_string_size (lit_get_magic_string_ex_utf8 (id))); ecma_magic_string_max_length = JERRY_MAX (ecma_magic_string_max_length, lit_magic_string_ex_sizes[id]); JERRY_ASSERT (ecma_magic_string_max_length <= LIT_MAGIC_STRING_LENGTH_LIMIT); } #endif /* !JERRY_NDEBUG */ } /* lit_magic_strings_ex_set */
/** * 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 */
/** * Get length of ecma-string * * @return number of characters in the string */ ecma_length_t ecma_string_get_length (const ecma_string_t *string_p) /**< ecma-string */ { switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { return (ecma_length_t) (string_p->u.utf8_string.length); } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { return ecma_string_get_number_in_desc_size (string_p->u.uint32_number); } case ECMA_STRING_CONTAINER_MAGIC_STRING: { JERRY_ASSERT (ECMA_STRING_IS_ASCII (lit_get_magic_string_utf8 (string_p->u.magic_string_id), lit_get_magic_string_size (string_p->u.magic_string_id))); return lit_get_magic_string_size (string_p->u.magic_string_id); } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); JERRY_ASSERT (ECMA_STRING_IS_ASCII (lit_get_magic_string_ex_utf8 (string_p->u.magic_string_ex_id), lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id))); return lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id); } } } /* ecma_string_get_length */
/** * Find a literal in literal storage. * Only charset and magic string records are checked during search. * * @return pointer to a literal or NULL if no corresponding literal exists */ literal_t lit_find_literal_by_utf8_string (const lit_utf8_byte_t *str_p, /**< a string to search for */ lit_utf8_size_t str_size) /**< length of the string */ { JERRY_ASSERT (str_p || !str_size); for (literal_t lit = lit_storage.get_first (); lit != NULL; lit = lit_storage.get_next (lit)) { rcs_record_t::type_t type = lit->get_type (); if (type == LIT_STR_T) { if (static_cast<lit_charset_record_t *>(lit)->get_length () != str_size) { continue; } if (!static_cast<lit_charset_record_t *>(lit)->compare_utf8 (str_p, str_size)) { return lit; } } else if (type == LIT_MAGIC_STR_T) { lit_magic_string_id_t magic_id = lit_magic_record_get_magic_str_id (lit); const lit_utf8_byte_t *magic_str_p = lit_get_magic_string_utf8 (magic_id); if (lit_zt_utf8_string_size (magic_str_p) != str_size) { continue; } if (!strncmp ((const char *) magic_str_p, (const char *) str_p, str_size)) { return lit; } } else if (type == LIT_MAGIC_STR_EX_T) { lit_magic_string_ex_id_t magic_id = lit_magic_record_ex_get_magic_str_id (lit); const lit_utf8_byte_t *magic_str_p = lit_get_magic_string_ex_utf8 (magic_id); if (lit_zt_utf8_string_size (magic_str_p) != str_size) { continue; } if (!strncmp ((const char *) magic_str_p, (const char *) str_p, str_size)) { return lit; } } } return NULL; } /* lit_find_literal_by_utf8_string */
/** * Compare utf-8 string and external magic string for equality * * @return true if strings are equal * false otherwise */ bool lit_compare_utf8_string_and_magic_string_ex (const lit_utf8_byte_t *string_p, /**< utf-8 string */ lit_utf8_size_t string_size, /**< string size in bytes */ lit_magic_string_ex_id_t magic_string_ex_id) /**< external magic string's * id */ { return lit_compare_utf8_strings (string_p, string_size, lit_get_magic_string_ex_utf8 (magic_string_ex_id), lit_get_magic_string_ex_size (magic_string_ex_id)); } /* lit_compare_utf8_string_and_magic_string_ex */
/** * Initialize external ecma-string descriptor with specified magic string */ static void ecma_init_ecma_string_from_magic_string_ex_id (ecma_string_t *string_p, /**< descriptor to initialize */ lit_magic_string_ex_id_t magic_string_ex_id) /**< identifier of the external magic string */ { string_p->refs_and_container = ECMA_STRING_CONTAINER_MAGIC_STRING_EX | ECMA_STRING_REF_ONE; string_p->hash = lit_utf8_string_calc_hash (lit_get_magic_string_ex_utf8 (magic_string_ex_id), lit_get_magic_string_ex_size (magic_string_ex_id)); string_p->u.common_field = 0; string_p->u.magic_string_ex_id = magic_string_ex_id; } /* ecma_init_ecma_string_from_magic_string_ex_id */
/** * Convert ecma-string's contents to a cesu-8 string and put it to the buffer. * It is the caller's responsibility to make sure that the string fits in the buffer. * * @return number of bytes, actually copied to the buffer. */ lit_utf8_size_t __attr_return_value_should_be_checked___ ecma_string_copy_to_utf8_buffer (const ecma_string_t *string_desc_p, /**< ecma-string descriptor */ lit_utf8_byte_t *buffer_p, /**< destination buffer pointer * (can be NULL if buffer_size == 0) */ lit_utf8_size_t buffer_size) /**< size of buffer */ { JERRY_ASSERT (string_desc_p != NULL); JERRY_ASSERT (string_desc_p->refs_and_container >= ECMA_STRING_REF_ONE); JERRY_ASSERT (buffer_p != NULL || buffer_size == 0); JERRY_ASSERT (ecma_string_get_size (string_desc_p) <= buffer_size); lit_utf8_size_t size; switch (ECMA_STRING_GET_CONTAINER (string_desc_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { size = string_desc_p->u.utf8_string.size; memcpy (buffer_p, string_desc_p + 1, size); break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { const uint32_t uint32_number = string_desc_p->u.uint32_number; size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size); break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { const lit_magic_string_id_t id = string_desc_p->u.magic_string_id; size = lit_get_magic_string_size (id); memcpy (buffer_p, lit_get_magic_string_utf8 (id), size); break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_desc_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); const lit_magic_string_ex_id_t id = string_desc_p->u.magic_string_ex_id; size = lit_get_magic_string_ex_size (id); memcpy (buffer_p, lit_get_magic_string_ex_utf8 (id), size); break; } } JERRY_ASSERT (size <= buffer_size); return size; } /* ecma_string_copy_to_utf8_buffer */
/** * 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 */
/** * Create new literal in literal storage from characters buffer. * Don't check if the same literal already exists. * * @return pointer to created record */ lit_literal_t lit_create_literal_from_utf8_string (const lit_utf8_byte_t *str_p, /**< string to initialize the record, * could be non-zero-terminated */ lit_utf8_size_t str_size) /**< length of the string */ { JERRY_ASSERT (str_p || !str_size); lit_magic_string_id_t m_str_id; for (m_str_id = (lit_magic_string_id_t) 0; m_str_id < LIT_MAGIC_STRING__COUNT; m_str_id = (lit_magic_string_id_t) (m_str_id + 1)) { if (lit_get_magic_string_size (m_str_id) != str_size) { continue; } if (!strncmp ((const char *) str_p, (const char *) lit_get_magic_string_utf8 (m_str_id), str_size)) { return lit_create_magic_literal (m_str_id); } } lit_magic_string_ex_id_t m_str_ex_id; for (m_str_ex_id = (lit_magic_string_ex_id_t) 0; m_str_ex_id < lit_get_magic_string_ex_count (); m_str_ex_id = (lit_magic_string_ex_id_t) (m_str_ex_id + 1)) { if (lit_get_magic_string_ex_size (m_str_ex_id) != str_size) { continue; } if (!strncmp ((const char *) str_p, (const char *) lit_get_magic_string_ex_utf8 (m_str_ex_id), str_size)) { return lit_create_magic_literal_ex (m_str_ex_id); } } return lit_create_charset_literal (str_p, str_size); } /* lit_create_literal_from_utf8_string */
/** * Check if two literals are equal * * @return true if equal * false otherwise */ bool lit_literal_equal (lit_literal_t lit1, /**< first literal */ lit_literal_t lit2) /**< second literal */ { switch (lit2->type) { case LIT_RECORD_TYPE_CHARSET: { return lit_literal_equal_charset_rec (lit1, lit2); } case LIT_RECORD_TYPE_MAGIC_STR: { lit_magic_string_id_t magic_str_id = lit_magic_literal_get_magic_str_id (lit2); return lit_literal_equal_utf8 (lit1, lit_get_magic_string_utf8 (magic_str_id), lit_get_magic_string_size (magic_str_id)); } case LIT_RECORD_TYPE_MAGIC_STR_EX: { lit_magic_string_ex_id_t magic_str_ex_id = lit_magic_literal_get_magic_str_ex_id (lit2); return lit_literal_equal_utf8 (lit1, lit_get_magic_string_ex_utf8 (magic_str_ex_id), lit_get_magic_string_ex_size (magic_str_ex_id)); } case LIT_RECORD_TYPE_NUMBER: { ecma_number_t num = lit_number_literal_get_number (lit2); return lit_literal_equal_num (lit1, num); } default: { JERRY_UNREACHABLE (); break; } } JERRY_UNREACHABLE (); return 0; } /* lit_literal_equal */
/** * 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 */
/** * Relational compare of ecma-strings. * * First string is less than second string if: * - strings are not equal; * - first string is prefix of second or is lexicographically less than second. * * @return true - if first string is less than second string, * false - otherwise. */ bool ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, /**< ecma-string */ const ecma_string_t *string2_p) /**< ecma-string */ { if (ecma_compare_ecma_strings (string1_p, string2_p)) { return false; } const lit_utf8_byte_t *utf8_string1_p, *utf8_string2_p; lit_utf8_size_t utf8_string1_size, utf8_string2_size; lit_utf8_byte_t uint32_to_string_buffer1[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; lit_utf8_byte_t uint32_to_string_buffer2[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; switch (ECMA_STRING_GET_CONTAINER (string1_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { utf8_string1_p = (lit_utf8_byte_t *) (string1_p + 1); utf8_string1_size = string1_p->u.utf8_string.size; break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { utf8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number, uint32_to_string_buffer1, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string1_p = uint32_to_string_buffer1; break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { utf8_string1_p = lit_get_magic_string_utf8 (string1_p->u.magic_string_id); utf8_string1_size = lit_get_magic_string_size (string1_p->u.magic_string_id); break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); utf8_string1_p = lit_get_magic_string_ex_utf8 (string1_p->u.magic_string_id); utf8_string1_size = lit_get_magic_string_ex_size (string1_p->u.magic_string_id); break; } } switch (ECMA_STRING_GET_CONTAINER (string2_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { utf8_string2_p = (lit_utf8_byte_t *) (string2_p + 1); utf8_string2_size = string2_p->u.utf8_string.size; break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { utf8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number, uint32_to_string_buffer2, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string2_p = uint32_to_string_buffer2; break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { utf8_string2_p = lit_get_magic_string_utf8 (string2_p->u.magic_string_id); utf8_string2_size = lit_get_magic_string_size (string2_p->u.magic_string_id); break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string2_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); utf8_string2_p = lit_get_magic_string_ex_utf8 (string2_p->u.magic_string_id); utf8_string2_size = lit_get_magic_string_ex_size (string2_p->u.magic_string_id); break; } } return lit_compare_utf8_strings_relational (utf8_string1_p, utf8_string1_size, utf8_string2_p, utf8_string2_size); } /* ecma_compare_ecma_strings_relational */
/** * Concatenate ecma-strings * * @return concatenation of two ecma-strings */ ecma_string_t * ecma_concat_ecma_strings (ecma_string_t *string1_p, /**< first ecma-string */ ecma_string_t *string2_p) /**< second ecma-string */ { JERRY_ASSERT (string1_p != NULL && string2_p != NULL); if (ecma_string_is_empty (string1_p)) { ecma_ref_ecma_string (string2_p); return string2_p; } else if (ecma_string_is_empty (string2_p)) { ecma_ref_ecma_string (string1_p); return string1_p; } const lit_utf8_byte_t *utf8_string1_p, *utf8_string2_p; lit_utf8_size_t utf8_string1_size, utf8_string2_size; lit_utf8_size_t utf8_string1_length, utf8_string2_length; lit_utf8_byte_t uint32_to_string_buffer1[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; lit_utf8_byte_t uint32_to_string_buffer2[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; switch (ECMA_STRING_GET_CONTAINER (string1_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { utf8_string1_p = (lit_utf8_byte_t *) (string1_p + 1); utf8_string1_size = string1_p->u.utf8_string.size; utf8_string1_length = string1_p->u.utf8_string.length; break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { utf8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number, uint32_to_string_buffer1, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string1_p = uint32_to_string_buffer1; utf8_string1_length = utf8_string1_size; break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { utf8_string1_p = lit_get_magic_string_utf8 (string1_p->u.magic_string_id); utf8_string1_size = lit_get_magic_string_size (string1_p->u.magic_string_id); utf8_string1_length = utf8_string1_size; break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); utf8_string1_p = lit_get_magic_string_ex_utf8 (string1_p->u.magic_string_id); utf8_string1_size = lit_get_magic_string_ex_size (string1_p->u.magic_string_id); utf8_string1_length = utf8_string1_size; break; } } switch (ECMA_STRING_GET_CONTAINER (string2_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { utf8_string2_p = (lit_utf8_byte_t *) (string2_p + 1); utf8_string2_size = string2_p->u.utf8_string.size; utf8_string2_length = string2_p->u.utf8_string.length; break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { utf8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number, uint32_to_string_buffer2, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string2_p = uint32_to_string_buffer2; utf8_string2_length = utf8_string2_size; break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { utf8_string2_p = lit_get_magic_string_utf8 (string2_p->u.magic_string_id); utf8_string2_size = lit_get_magic_string_size (string2_p->u.magic_string_id); utf8_string2_length = utf8_string2_size; break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string2_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); utf8_string2_p = lit_get_magic_string_ex_utf8 (string2_p->u.magic_string_id); utf8_string2_size = lit_get_magic_string_ex_size (string2_p->u.magic_string_id); utf8_string2_length = utf8_string2_size; break; } } JERRY_ASSERT (utf8_string1_size > 0); JERRY_ASSERT (utf8_string2_size > 0); JERRY_ASSERT (utf8_string1_length <= utf8_string1_size); JERRY_ASSERT (utf8_string2_length <= utf8_string2_size); lit_utf8_size_t new_size = utf8_string1_size + utf8_string2_size; JERRY_ASSERT (new_size <= UINT16_MAX); ecma_string_t *string_desc_p = jmem_heap_alloc_block (sizeof (ecma_string_t) + new_size); string_desc_p->refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE; string_desc_p->hash = lit_utf8_string_hash_combine (string1_p->hash, utf8_string2_p, utf8_string2_size); string_desc_p->u.common_field = 0; string_desc_p->u.utf8_string.size = (uint16_t) new_size; string_desc_p->u.utf8_string.length = (uint16_t) (utf8_string1_length + utf8_string2_length); lit_utf8_byte_t *data_p = (lit_utf8_byte_t *) (string_desc_p + 1); memcpy (data_p, utf8_string1_p, utf8_string1_size); memcpy (data_p + utf8_string1_size, utf8_string2_p, utf8_string2_size); return string_desc_p; } /* ecma_concat_ecma_strings */
/** * Find a literal in literal storage. * Only charset and magic string records are checked during search. * * @return pointer to a literal or NULL if no corresponding literal exists */ lit_literal_t lit_find_literal_by_utf8_string (const lit_utf8_byte_t *str_p, /**< a string to search for */ lit_utf8_size_t str_size) /**< length of the string */ { JERRY_ASSERT (str_p || !str_size); lit_string_hash_t str_hash = lit_utf8_string_calc_hash (str_p, str_size); lit_literal_t lit; for (lit = lit_storage; lit != NULL; lit = lit_cpointer_decompress (lit->next)) { const lit_record_type_t type = (lit_record_type_t) lit->type; switch (type) { case LIT_RECORD_TYPE_CHARSET: { const lit_charset_record_t *const rec_p = (const lit_charset_record_t *) lit; if (rec_p->hash != str_hash) { continue; } if (rec_p->size != str_size) { continue; } if (!strncmp ((const char *) (rec_p + 1), (const char *) str_p, str_size)) { return lit; } break; } case LIT_RECORD_TYPE_MAGIC_STR: { lit_magic_string_id_t magic_id = (lit_magic_string_id_t) ((lit_magic_record_t *) lit)->magic_id; const lit_utf8_byte_t *magic_str_p = lit_get_magic_string_utf8 (magic_id); if (lit_get_magic_string_size (magic_id) != str_size) { continue; } if (!strncmp ((const char *) magic_str_p, (const char *) str_p, str_size)) { return lit; } break; } case LIT_RECORD_TYPE_MAGIC_STR_EX: { lit_magic_string_ex_id_t magic_id = ((lit_magic_record_t *) lit)->magic_id; const lit_utf8_byte_t *magic_str_p = lit_get_magic_string_ex_utf8 (magic_id); if (lit_get_magic_string_ex_size (magic_id) != str_size) { continue; } if (!strncmp ((const char *) magic_str_p, (const char *) str_p, str_size)) { return lit; } break; } default: { JERRY_ASSERT (type == LIT_RECORD_TYPE_NUMBER); break; } } } return NULL; } /* lit_find_literal_by_utf8_string */
/** * Check if string is array index. * * @return true - if string is valid array index * false - otherwise */ bool ecma_string_get_array_index (const ecma_string_t *str_p, /**< ecma-string */ uint32_t *out_index_p) /**< [out] index */ { const ecma_string_container_t type = ECMA_STRING_GET_CONTAINER (str_p); if (type == ECMA_STRING_CONTAINER_UINT32_IN_DESC) { const uint32_t index = str_p->u.uint32_number; *out_index_p = index; return index != UINT32_MAX; } else if (type == ECMA_STRING_CONTAINER_MAGIC_STRING) { return false; } else { lit_utf8_size_t size; const lit_utf8_byte_t *raw_str_p; if (unlikely (type == ECMA_STRING_CONTAINER_MAGIC_STRING_EX)) { size = lit_get_magic_string_ex_size (str_p->u.magic_string_ex_id); raw_str_p = lit_get_magic_string_ex_utf8 (str_p->u.magic_string_ex_id); } else { JERRY_ASSERT (type == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING); size = str_p->u.utf8_string.size; raw_str_p = (const lit_utf8_byte_t *) (str_p + 1); } if (*raw_str_p == LIT_CHAR_0) { *out_index_p = 0; return size == 1; } if (size > 10) { return false; } uint32_t index = 0; const lit_utf8_size_t end = (size == 10) ? 9 : size; for (lit_utf8_size_t i = 0; i < end; i++) { if (raw_str_p[i] > LIT_CHAR_9 || raw_str_p[i] < LIT_CHAR_0) { return false; } index = (index * 10) + (uint32_t) (raw_str_p[i] - LIT_CHAR_0); } if (size == 10) { if (index > UINT32_MAX / 10 || raw_str_p[9] > LIT_CHAR_9 || raw_str_p[9] < LIT_CHAR_0) { return false; } index *= 10; const uint32_t digit = (uint32_t) (raw_str_p[9] - LIT_CHAR_0); if (index >= UINT32_MAX - digit) { return false; } index += digit; } *out_index_p = index; return true; } } /* ecma_string_get_array_index */
/** * Returns with the raw byte array of the string, if it is available. * * @return byte array start - if the byte array of a string is available * NULL - otherwise */ const lit_utf8_byte_t * ecma_string_raw_chars (const ecma_string_t *string_p, /**< ecma-string */ lit_utf8_size_t *size_p, /**< [out] size of the ecma string */ bool *is_ascii_p) /**< [out] true, if the string is an ascii * character sequence (size == length) * false, otherwise */ { ecma_length_t length; lit_utf8_size_t size; const lit_utf8_byte_t *result_p; switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { size = string_p->u.utf8_string.size; length = string_p->u.utf8_string.length; result_p = (const lit_utf8_byte_t *) (string_p + 1); break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { size = (lit_utf8_size_t) ecma_string_get_number_in_desc_size (string_p->u.uint32_number); /* All numbers must be ascii strings. */ JERRY_ASSERT (ecma_string_get_length (string_p) == size); length = size; result_p = NULL; break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { size = lit_get_magic_string_size (string_p->u.magic_string_id); length = size; result_p = lit_get_magic_string_utf8 (string_p->u.magic_string_id); /* All magic strings must be ascii strings. */ JERRY_ASSERT (ECMA_STRING_IS_ASCII (result_p, size)); break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); size = lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id); length = size; result_p = lit_get_magic_string_ex_utf8 (string_p->u.magic_string_ex_id); /* All extended magic strings must be ascii strings. */ JERRY_ASSERT (ECMA_STRING_IS_ASCII (result_p, size)); break; } } *size_p = size; *is_ascii_p = (length == size); return result_p; } /* ecma_string_raw_chars */
/** * Long path part of ecma-string to ecma-string comparison routine * * See also: * ecma_compare_ecma_strings * * @return true - if strings are equal; * false - otherwise. */ static bool __attr_noinline___ ecma_compare_ecma_strings_longpath (const ecma_string_t *string1_p, /* ecma-string */ const ecma_string_t *string2_p) /* ecma-string */ { if (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_GET_CONTAINER (string2_p)) { switch (ECMA_STRING_GET_CONTAINER (string1_p)) { case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { JERRY_ASSERT (string1_p->u.uint32_number != string2_p->u.uint32_number); return false; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { JERRY_ASSERT (string1_p->u.magic_string_id != string2_p->u.magic_string_id); return false; } case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: { JERRY_ASSERT (string1_p->u.magic_string_ex_id != string2_p->u.magic_string_ex_id); return false; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_HEAP_UTF8_STRING); break; } } } const lit_utf8_byte_t *utf8_string1_p, *utf8_string2_p; lit_utf8_size_t utf8_string1_size, utf8_string2_size; lit_utf8_byte_t uint32_to_string_buffer1[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; lit_utf8_byte_t uint32_to_string_buffer2[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; switch (ECMA_STRING_GET_CONTAINER (string1_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { utf8_string1_p = (lit_utf8_byte_t *) (string1_p + 1); utf8_string1_size = string1_p->u.utf8_string.size; break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { utf8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number, uint32_to_string_buffer1, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string1_p = uint32_to_string_buffer1; break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { utf8_string1_p = lit_get_magic_string_utf8 (string1_p->u.magic_string_id); utf8_string1_size = lit_get_magic_string_size (string1_p->u.magic_string_id); break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); utf8_string1_p = lit_get_magic_string_ex_utf8 (string1_p->u.magic_string_id); utf8_string1_size = lit_get_magic_string_ex_size (string1_p->u.magic_string_id); break; } } switch (ECMA_STRING_GET_CONTAINER (string2_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { utf8_string2_p = (lit_utf8_byte_t *) (string2_p + 1); utf8_string2_size = string2_p->u.utf8_string.size; break; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { utf8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number, uint32_to_string_buffer2, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string2_p = uint32_to_string_buffer2; break; } case ECMA_STRING_CONTAINER_MAGIC_STRING: { utf8_string2_p = lit_get_magic_string_utf8 (string2_p->u.magic_string_id); utf8_string2_size = lit_get_magic_string_size (string2_p->u.magic_string_id); break; } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string2_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); utf8_string2_p = lit_get_magic_string_ex_utf8 (string2_p->u.magic_string_id); utf8_string2_size = lit_get_magic_string_ex_size (string2_p->u.magic_string_id); break; } } if (utf8_string1_size != utf8_string2_size) { return false; } return !strncmp ((char *) utf8_string1_p, (char *) utf8_string2_p, utf8_string1_size); } /* ecma_compare_ecma_strings_longpath */
/** * 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 */