/** * Compare ecma-string to ecma-string * * @return true - if strings are equal; * false - otherwise. */ bool __attr_always_inline___ ecma_compare_ecma_strings (const ecma_string_t *string1_p, /* ecma-string */ const ecma_string_t *string2_p) /* ecma-string */ { JERRY_ASSERT (string1_p != NULL && string2_p != NULL); if (string1_p == string2_p) { return true; } if (string1_p->hash != string2_p->hash) { return false; } ecma_string_container_t string1_container = ECMA_STRING_GET_CONTAINER (string1_p); if (string1_container != ECMA_STRING_CONTAINER_HEAP_UTF8_STRING && string1_container == ECMA_STRING_GET_CONTAINER (string2_p)) { return string1_p->u.common_field == string2_p->u.common_field; } return ecma_compare_ecma_strings_longpath (string1_p, string2_p); } /* ecma_compare_ecma_strings */
/** * 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 */
/** * Lookup property in the LCache * * @return true - if (object, property name) pair is registered in LCache, * false - probably, not registered. */ inline bool __attr_always_inline___ ecma_lcache_lookup (ecma_object_t *object_p, /**< object */ const ecma_string_t *prop_name_p, /**< property's name */ ecma_property_t **prop_p_p) /**< [out] if return value is true, * then here will be pointer to property, * if the object contains property with specified name, * or, otherwise - NULL; * if return value is false, * then the output parameter is not set */ { #ifndef CONFIG_ECMA_LCACHE_DISABLE lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); unsigned int object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); for (uint32_t i = 0; i < ECMA_LCACHE_HASH_ROW_LENGTH; i++) { if (ecma_lcache_hash_table[hash_key][i].object_cp == object_cp) { ecma_string_t *entry_prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, ecma_lcache_hash_table[hash_key][i].prop_name_cp); JERRY_ASSERT (prop_name_p->hash == entry_prop_name_p->hash); if (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_GET_CONTAINER (entry_prop_name_p) && prop_name_p->u.common_field == entry_prop_name_p->u.common_field) { ecma_property_t *prop_p = ecma_lcache_hash_table[hash_key][i].prop_p; JERRY_ASSERT (prop_p == NULL || ecma_is_property_lcached (prop_p)); *prop_p_p = prop_p; return true; } else { /* may be equal but it is long to compare it here */ } } } #else /* CONFIG_ECMA_LCACHE_DISABLE */ (void) object_p; (void) prop_name_p; (void) prop_p_p; #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ return false; } /* ecma_lcache_lookup */
/** * 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 passed string equals to one of magic strings * and if equal magic string was found, return it's id in 'out_id_p' argument. * * @return true - if magic string equal to passed string was found, * false - otherwise. */ bool ecma_is_string_magic (const ecma_string_t *string_p, /**< ecma-string */ lit_magic_string_id_t *out_id_p) /**< [out] magic string's id */ { if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING) { JERRY_ASSERT (string_p->u.magic_string_id < LIT_MAGIC_STRING__COUNT); *out_id_p = (lit_magic_string_id_t) string_p->u.magic_string_id; return true; } else { /* * Any ecma-string constructor except ecma_concat_ecma_strings * should return ecma-string with ECMA_STRING_CONTAINER_MAGIC_STRING * container type if new ecma-string's content is equal to one of magic strings. */ #ifndef JERRY_NDEBUG JERRY_ASSERT (ecma_string_get_length (string_p) > LIT_MAGIC_STRING_LENGTH_LIMIT || !ecma_is_string_magic_longpath (string_p, out_id_p)); #endif /* !JERRY_NDEBUG */ return false; } } /* ecma_is_string_magic */
/** * Lookup property in the LCache * * @return a pointer to an ecma_property_t if the lookup is successful * NULL otherwise */ inline ecma_property_t * __attr_always_inline___ ecma_lcache_lookup (ecma_object_t *object_p, /**< object */ const ecma_string_t *prop_name_p) /**< property's name */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_name_p != NULL); #ifndef CONFIG_ECMA_LCACHE_DISABLE jmem_cpointer_t object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); size_t row_index = ecma_lcache_row_index (object_cp, prop_name_p); ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index]; ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH; ecma_string_container_t prop_container = ECMA_STRING_GET_CONTAINER (prop_name_p); while (entry_p < entry_end_p) { if (entry_p->object_cp == object_cp) { ecma_string_t *entry_prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, entry_p->prop_name_cp); JERRY_ASSERT ((prop_name_p->hash & ECMA_LCACHE_HASH_MASK) == (entry_prop_name_p->hash & ECMA_LCACHE_HASH_MASK)); if (prop_name_p == entry_prop_name_p || (prop_container > ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING && prop_container == ECMA_STRING_GET_CONTAINER (entry_prop_name_p) && prop_name_p->u.common_field == entry_prop_name_p->u.common_field)) { ecma_property_t *prop_p = entry_p->prop_p; JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p)); return prop_p; } else { /* They can be equal, but generic string comparison is too costly. */ } } entry_p++; } #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ return NULL; } /* ecma_lcache_lookup */
/** * Get size of ecma-string * * @return number of bytes in the buffer needed to represent the string */ lit_utf8_size_t ecma_string_get_size (const ecma_string_t *string_p) /**< ecma-string */ { switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { return (lit_utf8_size_t) string_p->u.utf8_string.size; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { return (lit_utf8_size_t) ecma_string_get_number_in_desc_size (string_p->u.uint32_number); } case ECMA_STRING_CONTAINER_MAGIC_STRING: { 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); return lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id); } } } /* ecma_string_get_size */
/** * Print literal. */ void util_print_literal (lexer_literal_t *literal_p) /**< literal */ { if (literal_p->type == LEXER_IDENT_LITERAL) { if (literal_p->status_flags & LEXER_FLAG_VAR) { printf ("var_ident("); } else { printf ("ident("); } util_print_chars (literal_p->u.char_p, literal_p->prop.length); } else if (literal_p->type == LEXER_FUNCTION_LITERAL) { printf ("function"); return; } else if (literal_p->type == LEXER_STRING_LITERAL) { printf ("string("); util_print_chars (literal_p->u.char_p, literal_p->prop.length); } else if (literal_p->type == LEXER_NUMBER_LITERAL) { ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, literal_p->u.value); JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (value_p) == ECMA_STRING_LITERAL_NUMBER); printf ("number("); util_print_number (ecma_get_number_from_value (value_p->u.lit_number)); } else if (literal_p->type == LEXER_REGEXP_LITERAL) { printf ("regexp"); return; } else { printf ("unknown"); return; } printf (")"); } /* util_print_literal */
/** * Checks whether the string equals to "length". * * @return true if the string equals to "length" * false otherwise */ inline bool __attr_always_inline___ ecma_string_is_length (const ecma_string_t *string_p) /**< property name */ { ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (string_p); if (container == ECMA_STRING_CONTAINER_MAGIC_STRING) { return string_p->u.magic_string_id == LIT_MAGIC_STRING_LENGTH; } if (container != ECMA_STRING_CONTAINER_HEAP_UTF8_STRING || string_p->u.utf8_string.size != 6 || string_p->hash != LIT_STRING_LENGTH_HASH) { return false; } return !strncmp ((char *) (string_p + 1), "length", 6); } /* ecma_string_is_length */
/** * Decrease reference counter and deallocate ecma-string * if the counter becomes zero. */ void ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */ { JERRY_ASSERT (string_p != NULL); JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); /* Decrease reference counter. */ string_p->refs_and_container = (uint16_t) (string_p->refs_and_container - ECMA_STRING_REF_ONE); if (string_p->refs_and_container >= ECMA_STRING_REF_ONE) { return; } switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: { jmem_heap_free_block (string_p, string_p->u.utf8_string.size + sizeof (ecma_string_t)); return; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: case ECMA_STRING_CONTAINER_MAGIC_STRING: case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: { /* only the string descriptor itself should be freed */ break; } case ECMA_STRING_LITERAL_NUMBER: { ecma_fast_free_value (string_p->u.lit_number); break; } default: { JERRY_UNREACHABLE (); break; } } ecma_dealloc_string (string_p); } /* ecma_deref_ecma_string */
/** * Converts a string into a property name * * @return the compressed pointer part of the name */ static inline jmem_cpointer_t __attr_always_inline___ ecma_string_to_lcache_property_name (const ecma_string_t *prop_name_p, /**< property name */ ecma_property_t *name_type_p) /**< [out] property name type */ { ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (prop_name_p); switch (container) { case ECMA_STRING_CONTAINER_UINT32_IN_DESC: case ECMA_STRING_CONTAINER_MAGIC_STRING: case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: { #ifdef JERRY_CPOINTER_32_BIT *name_type_p = (ecma_property_t) container; return (jmem_cpointer_t) prop_name_p->u.uint32_number; #else /* !JERRY_CPOINTER_32_BIT */ if (prop_name_p->u.uint32_number < (UINT16_MAX + 1)) { *name_type_p = (ecma_property_t) container; return (jmem_cpointer_t) prop_name_p->u.uint32_number; } #endif /* JERRY_CPOINTER_32_BIT */ break; } default: { break; } } *name_type_p = ECMA_PROPERTY_NAME_TYPE_STRING; jmem_cpointer_t prop_name_cp; ECMA_SET_NON_NULL_POINTER (prop_name_cp, prop_name_p); return prop_name_cp; } /* ecma_string_to_lcache_property_name */
/** * Convert ecma-string to number */ ecma_number_t ecma_string_to_number (const ecma_string_t *str_p) /**< ecma-string */ { JERRY_ASSERT (str_p != NULL); switch (ECMA_STRING_GET_CONTAINER (str_p)) { case ECMA_STRING_CONTAINER_UINT32_IN_DESC: { return ((ecma_number_t) str_p->u.uint32_number); } case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: case ECMA_STRING_CONTAINER_MAGIC_STRING: case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: { ecma_number_t num; ECMA_STRING_TO_UTF8_STRING (str_p, str_buffer_p, str_buffer_size); if (str_buffer_size == 0) { return ECMA_NUMBER_ZERO; } num = ecma_utf8_string_to_number (str_buffer_p, str_buffer_size); ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size); return num; } default: { JERRY_UNREACHABLE (); } } } /* ecma_string_to_number */
/** * Get character from specified position in the ecma-string. * * @return character value */ ecma_char_t ecma_string_get_char_at_pos (const ecma_string_t *string_p, /**< ecma-string */ ecma_length_t index) /**< index of character */ { JERRY_ASSERT (index < ecma_string_get_length (string_p)); lit_utf8_size_t buffer_size; bool is_ascii; const lit_utf8_byte_t *chars_p = ecma_string_raw_chars (string_p, &buffer_size, &is_ascii); if (chars_p != NULL) { if (is_ascii) { return chars_p[index]; } return lit_utf8_string_code_unit_at (chars_p, buffer_size, index); } ecma_char_t ch; JMEM_DEFINE_LOCAL_ARRAY (utf8_str_p, buffer_size, lit_utf8_byte_t); ecma_string_to_utf8_bytes (string_p, utf8_str_p, buffer_size); JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC); /* Both above must be ascii strings. */ JERRY_ASSERT (is_ascii); ch = utf8_str_p[index]; JMEM_FINALIZE_LOCAL_ARRAY (utf8_str_p); return ch; } /* ecma_string_get_char_at_pos */
/** * Lazy instantation of non-builtin ecma function object's properties * * Warning: * Only non-configurable properties could be instantiated lazily in this function, * as configurable properties could be deleted and it would be incorrect * to reinstantiate them in the function in second time. * * @return pointer to newly instantiated property, if a property was instantiated, * NULL - otherwise */ ecma_property_t * ecma_op_function_try_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */ ecma_string_t *property_name_p) /**< property name */ { static const char prototype_str_p[] = "prototype"; JERRY_ASSERT (!ecma_get_object_is_builtin (object_p)); ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (property_name_p); /* Check whether the property_name_p is prototype */ if (container == ECMA_STRING_CONTAINER_MAGIC_STRING) { if (property_name_p->u.magic_string_id != LIT_MAGIC_STRING_PROTOTYPE) { return NULL; } } else if (container != ECMA_STRING_CONTAINER_HEAP_UTF8_STRING || property_name_p->u.utf8_string.size != (sizeof (prototype_str_p) - 1)) { return NULL; } else { if (strncmp ((char *) (property_name_p + 1), prototype_str_p, (sizeof (prototype_str_p) - 1)) != 0) { return NULL; } } /* ECMA-262 v5, 13.2, 16-18 */ /* 16. */ ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg (); /* 17. */ ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR); ecma_property_value_t *constructor_prop_value_p; constructor_prop_value_p = ecma_create_named_data_property (proto_object_p, magic_string_constructor_p, ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL); constructor_prop_value_p->value = ecma_make_object_value (object_p); ecma_deref_ecma_string (magic_string_constructor_p); /* 18. */ ecma_property_t *prototype_prop_p; ecma_property_value_t *prototype_prop_value_p; prototype_prop_value_p = ecma_create_named_data_property (object_p, property_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &prototype_prop_p); prototype_prop_value_p->value = ecma_make_object_value (proto_object_p); ecma_deref_object (proto_object_p); return prototype_prop_p; } /* ecma_op_function_try_lazy_instantiate_property */
/** * [[GetOwnProperty]] ecma String object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 15.5.5.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_property_t * ecma_op_string_object_get_own_property (ecma_object_t *obj_p, /**< a String object */ ecma_string_t *property_name_p) /**< property name */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_STRING); // 1. ecma_property_t *prop_p = ecma_op_general_object_get_own_property (obj_p, property_name_p); // 2. if (prop_p != NULL) { return prop_p; } // 3., 5. uint32_t uint32_index; ecma_string_t *new_prop_name_p; if (ECMA_STRING_GET_CONTAINER (property_name_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) { uint32_index = property_name_p->u.uint32_number; new_prop_name_p = property_name_p; ecma_ref_ecma_string (new_prop_name_p); } else { ecma_number_t index = ecma_string_to_number (property_name_p); uint32_index = ecma_number_to_uint32 (index); ecma_string_t *to_str_p = ecma_new_ecma_string_from_uint32 (uint32_index); bool are_equal = ecma_compare_ecma_strings (to_str_p, property_name_p); if (!are_equal) { ecma_deref_ecma_string (to_str_p); return NULL; } else { new_prop_name_p = to_str_p; } } // 4. ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); ecma_string_t *prim_value_str_p; prim_value_str_p = ecma_get_string_from_value (ecma_get_internal_property_value (prim_value_prop_p)); // 6. ecma_length_t length = ecma_string_get_length (prim_value_str_p); ecma_property_t *new_prop_p; if (uint32_index >= (uint32_t) length) { // 7. new_prop_p = NULL; } else { // 8. ecma_char_t c = ecma_string_get_char_at_pos (prim_value_str_p, uint32_index); // 9. ecma_string_t *new_prop_str_value_p = ecma_new_ecma_string_from_code_unit (c); new_prop_p = ecma_create_named_data_property (obj_p, new_prop_name_p, ECMA_PROPERTY_FLAG_ENUMERABLE); ecma_set_named_data_property_value (new_prop_p, ecma_make_string_value (new_prop_str_value_p)); } ecma_deref_ecma_string (new_prop_name_p); return new_prop_p; } /* ecma_op_string_object_get_own_property */
/** * 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 */
/** * 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 */
/** * 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 */
/** * Checks whether ecma string is empty or not * * @return true - if empty * false - otherwise */ bool ecma_string_is_empty (const ecma_string_t *str_p) /**< ecma-string */ { return (ECMA_STRING_GET_CONTAINER (str_p) == ECMA_STRING_CONTAINER_MAGIC_STRING && str_p->u.magic_string_id == LIT_MAGIC_STRING__EMPTY); } /* ecma_string_is_empty */
/** * 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 */
/** * 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 */