diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 7a218d511..6418f55b8 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -536,11 +536,14 @@ typedef struct */ typedef enum { + ECMA_STRING_CONTAINER_LIT_TABLE, /**< actual data is in literal table */ ECMA_STRING_CONTAINER_HEAP_CHUNKS, /**< actual data is on the heap in a ecma_collection_chunk_t chain */ - ECMA_STRING_CONTAINER_LIT_TABLE, /**< actual data is in literal table */ - ECMA_STRING_CONTAINER_IN_DESCRIPTOR, /**< actual data is locally in the string's descriptor */ - ECMA_STRING_CONTAINER_HEAP_NUMBER /**< actual data is on the heap as a ecma_number_t */ + ECMA_STRING_CONTAINER_HEAP_NUMBER, /**< actual data is on the heap as a ecma_number_t */ + ECMA_STRING_CONTAINER_CHARS_IN_DESC, /**< actual data are several characters + stored locally in the string's descriptor */ + ECMA_STRING_CONTAINER_UINT32_IN_DESC /**< actual data is UInt32-represeneted Number + stored locally in the string's descriptor */ } ecma_string_container_t; FIXME (Move to library that should define the type (libserializer /* ? */)) @@ -558,7 +561,7 @@ typedef struct unsigned int refs : CONFIG_ECMA_REFERENCE_COUNTER_WIDTH; /** Where the string's data is placed (ecma_string_container_t) */ - unsigned int container : 2; + unsigned int container : 3; /** Flag indicating whether the length field is valid */ unsigned int is_length_valid : 1; @@ -580,8 +583,11 @@ typedef struct /** Compressed pointer to an ecma_number_t */ unsigned int number_cp : ECMA_POINTER_FIELD_WIDTH; - /** Actual data if placed locally in the descriptor */ - ecma_char_t chars[ sizeof (uint64_t) - sizeof (uint32_t) ]; + /** Actual data placed locally in the descriptor */ + ecma_char_t chars[ sizeof (uint32_t) ]; + + /** UInt32-represented number placed locally in the descriptor */ + uint32_t uint32_number; } u; } ecma_string_t; diff --git a/src/libecmaobjects/ecma-helpers-conversion.c b/src/libecmaobjects/ecma-helpers-conversion.c index 214ad4955..ebad562f1 100644 --- a/src/libecmaobjects/ecma-helpers-conversion.c +++ b/src/libecmaobjects/ecma-helpers-conversion.c @@ -57,23 +57,29 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string /** * ECMA-defined conversion of UInt32 to String (zero-terminated). + * + * @return number of bytes copied to buffer */ -void +ecma_length_t ecma_uint32_to_string (uint32_t value, /**< value to convert */ ecma_char_t *out_buffer_p, /**< buffer for zero-terminated string */ - size_t buffer_size) /**< size of buffer */ + ssize_t buffer_size) /**< size of buffer */ { FIXME (Implement according to ECMA); ecma_char_t *p = (ecma_char_t*) ((uint8_t*) out_buffer_p + buffer_size) - 1; *p-- = '\0'; + ecma_length_t bytes_copied = 1; + do { JERRY_ASSERT (p != out_buffer_p); *p-- = (ecma_char_t) ("0123456789"[value % 10]); value /= 10; + + bytes_copied++; } while (value != 0); @@ -82,6 +88,8 @@ ecma_uint32_to_string (uint32_t value, /**< value to convert */ ssize_t bytes_to_move = ((uint8_t*) out_buffer_p + buffer_size) - (uint8_t*) p; __memmove (out_buffer_p, p, (size_t) bytes_to_move); } + + return bytes_copied; } /* ecma_uint32_to_string */ /** diff --git a/src/libecmaobjects/ecma-helpers-string.c b/src/libecmaobjects/ecma-helpers-string.c index 6a37b5556..e12c1579d 100644 --- a/src/libecmaobjects/ecma-helpers-string.c +++ b/src/libecmaobjects/ecma-helpers-string.c @@ -57,7 +57,7 @@ ecma_new_ecma_string (const ecma_char_t *string_p) /**< zero-terminated string * if (bytes_needed_for_current_string <= bytes_for_chars_in_string_descriptor) { - string_desc_p->container = ECMA_STRING_CONTAINER_IN_DESCRIPTOR; + string_desc_p->container = ECMA_STRING_CONTAINER_CHARS_IN_DESC; __memcpy (string_desc_p->u.chars, string_p, bytes_needed_for_current_string); return string_desc_p; @@ -99,12 +99,63 @@ ecma_new_ecma_string (const ecma_char_t *string_p) /**< zero-terminated string * * @return pointer to ecma-string descriptor */ ecma_string_t* -ecma_new_ecma_string_from_number (ecma_number_t num) /**< ecma-number */ +ecma_new_ecma_string_from_uint32 (uint32_t uint32_number) /**< UInt32-represented ecma-number */ { ecma_string_t* string_desc_p = ecma_alloc_string (); string_desc_p->refs = 1; - string_desc_p->length = 0; - string_desc_p->is_length_valid = false; + string_desc_p->container = ECMA_STRING_CONTAINER_UINT32_IN_DESC; + string_desc_p->u.uint32_number = uint32_number; + + const uint32_t max_uint32_len = 10; + const uint32_t nums_with_ascending_length[10] = + { + 1u, + 10u, + 100u, + 1000u, + 10000u, + 100000u, + 1000000u, + 10000000u, + 100000000u, + 1000000000u + }; + + string_desc_p->length = 1; + + while (string_desc_p->length < max_uint32_len + && uint32_number >= nums_with_ascending_length [string_desc_p->length]) + { + string_desc_p->length++; + } + string_desc_p->is_length_valid = true; + + return string_desc_p; +} /* ecma_new_ecma_string_from_uint32 */ + +/** + * 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_uint32_to_number (uint32_num)) + { + return ecma_new_ecma_string_from_uint32 (uint32_num); + } + + ecma_char_t buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER + 1]; + ecma_length_t length = ecma_number_to_zt_string (num, + buffer, + sizeof (buffer)); + + ecma_string_t* string_desc_p = ecma_alloc_string (); + string_desc_p->refs = 1; + string_desc_p->length = length; + string_desc_p->is_length_valid = true; string_desc_p->container = ECMA_STRING_CONTAINER_HEAP_NUMBER; ecma_number_t *num_p = ecma_alloc_number (); @@ -197,7 +248,7 @@ ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */ } else { - JERRY_ASSERT (string_p->container == ECMA_STRING_CONTAINER_IN_DESCRIPTOR + JERRY_ASSERT (string_p->container == ECMA_STRING_CONTAINER_CHARS_IN_DESC || string_p->container == ECMA_STRING_CONTAINER_LIT_TABLE); /* only the string descriptor itself should be freed */ @@ -206,42 +257,6 @@ ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */ ecma_dealloc_string (string_p); } /* ecma_deref_ecma_string */ -/** - * Get length of the ecma-string - * - * @return length - */ -ecma_length_t -ecma_get_ecma_string_length (ecma_string_t *string_desc_p) /**< ecma-string descriptor */ -{ - switch ((ecma_string_container_t)string_desc_p->container) - { - case ECMA_STRING_CONTAINER_HEAP_CHUNKS: - case ECMA_STRING_CONTAINER_LIT_TABLE: - case ECMA_STRING_CONTAINER_IN_DESCRIPTOR: - { - JERRY_ASSERT (string_desc_p->is_length_valid); - - return string_desc_p->length; - } - - case ECMA_STRING_CONTAINER_HEAP_NUMBER: - { - if (string_desc_p->is_length_valid) - { - return string_desc_p->length; - } - else - { - /* calculate length */ - JERRY_UNIMPLEMENTED(); - } - } - } - - JERRY_UNREACHABLE(); -} /* ecma_get_ecma_string_length */ - /** * Convert ecma-string to number */ @@ -249,8 +264,15 @@ ecma_number_t ecma_string_to_number (ecma_string_t *str_p) /**< ecma-string */ { JERRY_ASSERT (str_p != NULL); + JERRY_ASSERT (str_p->is_length_valid); - if (str_p->container == ECMA_STRING_CONTAINER_HEAP_NUMBER) + if (str_p->container == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + { + uint32_t uint32_number = str_p->u.uint32_number; + + return ecma_uint32_to_number (uint32_number); + } + else if (str_p->container == ECMA_STRING_CONTAINER_HEAP_NUMBER) { ecma_number_t *num_p = ECMA_GET_POINTER (str_p->u.number_cp); @@ -258,8 +280,6 @@ ecma_string_to_number (ecma_string_t *str_p) /**< ecma-string */ } else { - JERRY_ASSERT (str_p->is_length_valid); - ecma_char_t zt_string_buffer [str_p->length + 1]; ssize_t bytes_copied = ecma_string_to_zt_string (str_p, @@ -277,31 +297,9 @@ ecma_string_to_number (ecma_string_t *str_p) /**< ecma-string */ static ssize_t ecma_string_get_required_buffer_size_for_zt_form (const ecma_string_t *string_desc_p) /**< ecma-string */ { - ecma_length_t string_length = 0; + JERRY_ASSERT (string_desc_p->is_length_valid); - switch ((ecma_string_container_t)string_desc_p->container) - { - case ECMA_STRING_CONTAINER_IN_DESCRIPTOR: - case ECMA_STRING_CONTAINER_HEAP_CHUNKS: - case ECMA_STRING_CONTAINER_LIT_TABLE: - { - JERRY_ASSERT (string_desc_p->is_length_valid); - - string_length = string_desc_p->length; - - break; - } - - case ECMA_STRING_CONTAINER_HEAP_NUMBER: - { - string_length = (string_desc_p->is_length_valid ? - string_desc_p->length : ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER); - - break; - } - } - - return (ssize_t) ((ssize_t) sizeof (ecma_char_t) * (string_length + 1)); + return (ssize_t) ((string_desc_p->length + 1u) * sizeof (ecma_char_t)); } /* ecma_string_get_required_buffer_size_for_zt_form */ /** @@ -322,6 +320,7 @@ ecma_string_to_zt_string (ecma_string_t *string_desc_p, /**< ecma-string descrip JERRY_ASSERT (string_desc_p->refs > 0); JERRY_ASSERT (buffer_p != NULL); JERRY_ASSERT (buffer_size > 0); + JERRY_ASSERT (string_desc_p->is_length_valid); ssize_t required_buffer_size = ecma_string_get_required_buffer_size_for_zt_form (string_desc_p); ssize_t bytes_copied = 0; @@ -335,9 +334,8 @@ ecma_string_to_zt_string (ecma_string_t *string_desc_p, /**< ecma-string descrip switch ((ecma_string_container_t)string_desc_p->container) { - case ECMA_STRING_CONTAINER_IN_DESCRIPTOR: + case ECMA_STRING_CONTAINER_CHARS_IN_DESC: { - JERRY_ASSERT (string_desc_p->is_length_valid); ecma_length_t string_length = string_desc_p->length; __memcpy (dest_p, string_desc_p->u.chars, string_length * sizeof (ecma_char_t)); @@ -349,7 +347,6 @@ ecma_string_to_zt_string (ecma_string_t *string_desc_p, /**< ecma-string descrip } case ECMA_STRING_CONTAINER_HEAP_CHUNKS: { - JERRY_ASSERT (string_desc_p->is_length_valid); ecma_length_t string_length = string_desc_p->length; ecma_collection_chunk_t *string_chunk_p = ECMA_GET_POINTER (string_desc_p->u.chunk_cp); @@ -382,26 +379,20 @@ ecma_string_to_zt_string (ecma_string_t *string_desc_p, /**< ecma-string descrip break; } + case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + { + uint32_t uint32_number = string_desc_p->u.uint32_number; + bytes_copied = ecma_uint32_to_string (uint32_number, buffer_p, required_buffer_size); + + break; + } case ECMA_STRING_CONTAINER_HEAP_NUMBER: { - const ssize_t buffer_size_required = (ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER + 1) * sizeof (ecma_char_t); - if (buffer_size_required < buffer_size) - { - return -(ssize_t) buffer_size_required; - } - ecma_number_t *num_p = ECMA_GET_POINTER (string_desc_p->u.number_cp); ecma_length_t length = ecma_number_to_zt_string (*num_p, buffer_p, buffer_size); - if (!string_desc_p->is_length_valid) - { - string_desc_p->length = length; - string_desc_p->is_length_valid = true; - } - - JERRY_ASSERT (string_desc_p->is_length_valid - && string_desc_p->length == length); + JERRY_ASSERT (string_desc_p->length == length); bytes_copied = (length + 1) * ((ssize_t) sizeof (ecma_char_t)); } @@ -626,19 +617,17 @@ ecma_compare_ecma_string_to_ecma_string (ecma_string_t *string1_p, /* ecma-strin ecma_string_t *string2_p) /* ecma-string */ { JERRY_ASSERT (string1_p != NULL && string2_p != NULL); + JERRY_ASSERT (string1_p->is_length_valid + && string2_p->is_length_valid); if (unlikely (string1_p == string2_p)) { return true; } - if (string1_p->is_length_valid - && string2_p->is_length_valid) + if (likely (string1_p->length != string2_p->length)) { - if (likely (string1_p->length != string2_p->length)) - { - return false; - } + return false; } if (string1_p->container == string2_p->container) @@ -661,10 +650,8 @@ ecma_compare_ecma_string_to_ecma_string (ecma_string_t *string1_p, /* ecma-strin return (*num1_p == *num2_p); } - else if (string1_p->container == ECMA_STRING_CONTAINER_IN_DESCRIPTOR) + else if (string1_p->container == ECMA_STRING_CONTAINER_CHARS_IN_DESC) { - JERRY_ASSERT (string1_p->is_length_valid); - JERRY_ASSERT (string2_p->is_length_valid); JERRY_ASSERT (string1_p->length == string2_p->length); return (__memcmp (string1_p->u.chars, string2_p->u.chars, string1_p->length * sizeof (ecma_char_t)) == 0); diff --git a/src/libecmaobjects/ecma-helpers.h b/src/libecmaobjects/ecma-helpers.h index 09c457f09..33fe2271d 100644 --- a/src/libecmaobjects/ecma-helpers.h +++ b/src/libecmaobjects/ecma-helpers.h @@ -88,11 +88,11 @@ extern bool ecma_is_empty_completion_value (ecma_completion_value_t value); /* ecma-helpers-string.c */ extern ecma_string_t* ecma_new_ecma_string (const ecma_char_t *string_p); +extern ecma_string_t* ecma_new_ecma_string_from_uint32 (uint32_t uint_number); extern ecma_string_t* ecma_new_ecma_string_from_number (ecma_number_t number); extern ecma_string_t* ecma_new_ecma_string_from_lit_index (literal_index_t lit_index); extern void ecma_ref_ecma_string (ecma_string_t *string_desc_p); extern void ecma_deref_ecma_string (ecma_string_t *string_p); -extern ecma_length_t ecma_get_ecma_string_length (ecma_string_t *string_desc_p); extern ecma_number_t ecma_string_to_number (ecma_string_t *str_p); extern ssize_t ecma_string_to_zt_string (ecma_string_t *string_desc_p, ecma_char_t *buffer_p, @@ -187,7 +187,7 @@ extern ecma_property_descriptor_t ecma_make_empty_property_descriptor (void); /* ecma-helpers-conversion.c */ extern ecma_number_t ecma_zt_string_to_number (const ecma_char_t *str_p); -extern void ecma_uint32_to_string (uint32_t value, ecma_char_t *out_buffer_p, size_t buffer_size); +extern ecma_length_t ecma_uint32_to_string (uint32_t value, ecma_char_t *out_buffer_p, ssize_t buffer_size); extern uint32_t ecma_number_to_uint32 (ecma_number_t value); extern int32_t ecma_number_to_int32 (ecma_number_t value); extern ecma_number_t ecma_int32_to_number (int32_t value);