ecma_stringbuilder_finalize (ecma_stringbuilder_t *builder_p) /**< string builder */
{
  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
  JERRY_ASSERT (header_p != NULL);

  const lit_utf8_size_t string_size = ECMA_STRINGBUILDER_STRING_SIZE (header_p);
  lit_utf8_byte_t *string_begin_p = ECMA_STRINGBUILDER_STRING_PTR (header_p);

  ecma_string_t *string_p = ecma_find_special_string (string_begin_p, string_size);

  if (JERRY_UNLIKELY (string_p != NULL))
  {
    ecma_stringbuilder_destroy (builder_p);
    return string_p;
  }

#ifndef JERRY_NDEBUG
  builder_p->header_p = NULL;
#endif

  size_t container_size = sizeof (ecma_short_string_t);
  const lit_string_hash_t hash = lit_utf8_string_calc_hash (string_begin_p, string_size);
  const lit_utf8_size_t length = lit_utf8_string_length (string_begin_p, string_size);

  if (JERRY_LIKELY (string_size <= UINT16_MAX))
  {
    if (JERRY_LIKELY (length == string_size) && string_size <= (UINT8_MAX + 1))
    {
      string_p = (ecma_string_t *) header_p;
      string_p->refs_and_container = ECMA_STRING_CONTAINER_HEAP_ASCII_STRING | ECMA_STRING_REF_ONE;
      string_p->u.hash = hash;
      ECMA_ASCII_STRING_SET_SIZE (string_p, string_size);

      return (ecma_string_t *) string_p;
    }
  }
  else
  {
    container_size = sizeof (ecma_long_string_t);
  }

  const size_t utf8_string_size = string_size + container_size;
  header_p = jmem_heap_realloc_block (header_p, header_p->current_size, utf8_string_size);
  memmove (((lit_utf8_byte_t *) header_p + container_size),
           ECMA_STRINGBUILDER_STRING_PTR (header_p),
           string_size);

#if JERRY_MEM_STATS
  jmem_stats_allocate_string_bytes (container_size - ECMA_ASCII_STRING_HEADER_SIZE);
#endif /* JERRY_MEM_STATS */

  if (JERRY_LIKELY (string_size <= UINT16_MAX))
  {
    ecma_short_string_t *short_string_p = (ecma_short_string_t *) header_p;

    short_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE;
    short_string_p->header.u.hash = hash;
    short_string_p->size = (uint16_t) string_size;
    short_string_p->length = (uint16_t) length;

    return (ecma_string_t *) short_string_p;
  }

  ecma_long_string_t *long_string_p = (ecma_long_string_t *) header_p;

  long_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_LONG_OR_EXTERNAL_STRING | ECMA_STRING_REF_ONE;
  long_string_p->header.u.hash = hash;
  long_string_p->string_p = ECMA_LONG_STRING_BUFFER_START (long_string_p);
  long_string_p->size = string_size;
  long_string_p->length = length;

  return (ecma_string_t *) long_string_p;
} /* ecma_stringbuilder_finalize */
ecma_stringbuilder_finalize (ecma_stringbuilder_t *builder_p)  
{
  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
  JERRY_ASSERT (header_p != NULL);

  const lit_utf8_size_t string_size = ECMA_STRINGBUILDER_STRING_SIZE (header_p);
  lit_utf8_byte_t *string_begin_p = ECMA_STRINGBUILDER_STRING_PTR (header_p);

  ecma_string_t *string_p = ecma_find_special_string (string_begin_p, string_size);

  if (JERRY_UNLIKELY (string_p != NULL))
  {
    ecma_stringbuilder_destroy (builder_p);
    return string_p;
  }

#ifndef JERRY_NDEBUG
  builder_p->header_p = NULL;
#endif

  size_t container_size = sizeof (ecma_short_string_t);
  const lit_string_hash_t hash = lit_utf8_string_calc_hash (string_begin_p, string_size);
  const lit_utf8_size_t length = lit_utf8_string_length (string_begin_p, string_size);

  if (JERRY_LIKELY (string_size <= UINT16_MAX))
  {
    if (JERRY_LIKELY (length == string_size) && string_size <= (UINT8_MAX + 1))
    {
      string_p = (ecma_string_t *) header_p;
      string_p->refs_and_container = ECMA_STRING_CONTAINER_HEAP_ASCII_STRING | ECMA_STRING_REF_ONE;
      string_p->u.hash = hash;
      ECMA_ASCII_STRING_SET_SIZE (string_p, string_size);

      return (ecma_string_t *) string_p;
    }
  }
  else
  {
    container_size = sizeof (ecma_long_string_t);
  }

  const size_t utf8_string_size = string_size + container_size;
  header_p = jmem_heap_realloc_block (header_p, header_p->current_size, utf8_string_size);
  memmove (((lit_utf8_byte_t *) header_p + container_size),
           ECMA_STRINGBUILDER_STRING_PTR (header_p),
           string_size);

#if JERRY_MEM_STATS
  jmem_stats_allocate_string_bytes (container_size - ECMA_ASCII_STRING_HEADER_SIZE);
#endif  

  if (JERRY_LIKELY (string_size <= UINT16_MAX))
  {
    ecma_short_string_t *short_string_p = (ecma_short_string_t *) header_p;

    short_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE;
    short_string_p->header.u.hash = hash;
    short_string_p->size = (uint16_t) string_size;
    short_string_p->length = (uint16_t) length;

    return (ecma_string_t *) short_string_p;
  }

  ecma_long_string_t *long_string_p = (ecma_long_string_t *) header_p;

  long_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_LONG_OR_EXTERNAL_STRING | ECMA_STRING_REF_ONE;
  long_string_p->header.u.hash = hash;
  long_string_p->string_p = ECMA_LONG_STRING_BUFFER_START (long_string_p);
  long_string_p->size = string_size;
  long_string_p->length = length;

  return (ecma_string_t *) long_string_p;
}  