diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index f17d661db9..bdce0bcaa1 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -28,7 +28,6 @@ #include "lit-globals.h" #include "lit-magic-strings.h" #include "mem-allocator.h" -#include "rcs-recordset.h" /** \addtogroup compressedpointer Compressed pointer * @{ @@ -787,16 +786,6 @@ typedef enum ECMA_STRING_CONTAINER_MAGIC_STRING_EX /**< the ecma-string is equal to one of external magic strings */ } ecma_string_container_t; -FIXME (Move to library that should define the type (literal.h /* ? */)) - -/** - * Literal and compressed pointer to literal - */ -typedef rcs_record_t *literal_t; -typedef rcs_cpointer_t lit_cpointer_t; - -#define NOT_A_LITERAL (lit_cpointer_t::null_cp ()) - /** * ECMA string-value descriptor */ diff --git a/jerry-core/ecma/base/ecma-helpers-string.cpp b/jerry-core/ecma/base/ecma-helpers-string.cpp index d2169d662b..4e637b988c 100644 --- a/jerry-core/ecma/base/ecma-helpers-string.cpp +++ b/jerry-core/ecma/base/ecma-helpers-string.cpp @@ -31,6 +31,7 @@ #include "lit-char-helpers.h" #include "lit-magic-strings.h" #include "vm.h" +#include "rcs-records.h" /** * Maximum length of strings' concatenation @@ -328,24 +329,27 @@ ecma_init_ecma_string_from_lit_cp (ecma_string_t *string_p, /**< descriptor to i JERRY_ASSERT (is_stack_var == (!mem_is_heap_pointer (string_p))); #endif /* !JERRY_NDEBUG */ - literal_t lit = lit_get_literal_by_cp (lit_cp); - if (lit->get_type () == LIT_MAGIC_STR_T) + lit_literal_t lit = lit_get_literal_by_cp (lit_cp); + rcs_record_type_t type = rcs_record_get_type (lit); + + if (RCS_RECORD_TYPE_IS_MAGIC_STR (type)) { ecma_init_ecma_string_from_magic_string_id (string_p, - lit_magic_record_get_magic_str_id (lit), + lit_magic_literal_get_magic_str_id (lit), is_stack_var); return; } - else if (lit->get_type () == LIT_MAGIC_STR_EX_T) + + if (RCS_RECORD_TYPE_IS_MAGIC_STR_EX (type)) { ecma_init_ecma_string_from_magic_string_ex_id (string_p, - lit_magic_record_ex_get_magic_str_id (lit), + lit_magic_literal_ex_get_magic_str_id (lit), is_stack_var); return; } - JERRY_ASSERT (lit->get_type () == LIT_STR_T); + JERRY_ASSERT (RCS_RECORD_TYPE_IS_CHARSET (type)); string_p->refs = 1; string_p->is_stack_var = (is_stack_var != 0); @@ -972,8 +976,8 @@ ecma_string_to_utf8_string (const ecma_string_t *string_desc_p, /**< ecma-string } case ECMA_STRING_CONTAINER_LIT_TABLE: { - literal_t lit = lit_get_literal_by_cp (string_desc_p->u.lit_cp); - JERRY_ASSERT (lit->get_type () == LIT_STR_T); + lit_literal_t lit = lit_get_literal_by_cp (string_desc_p->u.lit_cp); + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (lit)); lit_literal_to_utf8_string (lit, buffer_p, (size_t) required_buffer_size); break; } @@ -1308,9 +1312,9 @@ ecma_string_get_length (const ecma_string_t *string_p) /**< ecma-string */ if (container == ECMA_STRING_CONTAINER_LIT_TABLE) { - literal_t lit = lit_get_literal_by_cp (string_p->u.lit_cp); - JERRY_ASSERT (lit->get_type () == LIT_STR_T); - return lit_charset_record_get_length (lit); + lit_literal_t lit = lit_get_literal_by_cp (string_p->u.lit_cp); + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (lit)); + return lit_charset_literal_get_length (lit); } else if (container == ECMA_STRING_CONTAINER_MAGIC_STRING) { @@ -1385,10 +1389,10 @@ ecma_string_get_size (const ecma_string_t *string_p) /**< ecma-string */ if (container == ECMA_STRING_CONTAINER_LIT_TABLE) { - literal_t lit = lit_get_literal_by_cp (string_p->u.lit_cp); - JERRY_ASSERT (lit->get_type () == LIT_STR_T); + lit_literal_t lit = lit_get_literal_by_cp (string_p->u.lit_cp); + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (lit)); - return lit_charset_record_get_size (lit); + return lit_charset_literal_get_size (lit); } else if (container == ECMA_STRING_CONTAINER_MAGIC_STRING) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-global.cpp index dbabe52a18..9d9e0ff670 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.cpp @@ -29,6 +29,7 @@ #include "lit-strings.h" #include "vm.h" #include "jrt-libc-includes.h" +#include "jrt-bit-fields.h" #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index af7dfbbb6b..e74ba5cb30 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -28,7 +28,6 @@ #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-try-catch-macro.h" -#include "lit-literal.h" #include "lit-magic-strings.h" #include "parser.h" @@ -1679,7 +1678,8 @@ jerry_parse_and_save_snapshot (const jerry_api_char_t* source_p, /**< script sou if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, &buffer_write_offset, - version)) + &version, + sizeof (version))) { return 0; } @@ -1732,7 +1732,7 @@ jerry_parse_and_save_snapshot (const jerry_api_char_t* source_p, /**< script sou return 0; } - is_ok = jrt_write_to_buffer_by_offset (buffer_p, buffer_size, &header_offset, header); + is_ok = jrt_write_to_buffer_by_offset (buffer_p, buffer_size, &header_offset, &header, sizeof (header)); JERRY_ASSERT (is_ok && header_offset < buffer_write_offset); return buffer_write_offset; @@ -1777,7 +1777,8 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */ if (!jrt_read_from_buffer_by_offset (snapshot_data_p, snapshot_size, &snapshot_read, - &version)) + &version, + sizeof (version))) { return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT; } @@ -1806,8 +1807,7 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */ if (!lit_load_literals_from_snapshot (snapshot_data_p + snapshot_read, header_p->lit_table_size, &lit_map_p, - &literals_num, - is_copy)) + &literals_num)) { JERRY_ASSERT (lit_map_p == NULL); return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT; diff --git a/jerry-core/jrt/jrt.h b/jerry-core/jrt/jrt.h index 5745ec40fc..f8da01a02c 100644 --- a/jerry-core/jrt/jrt.h +++ b/jerry-core/jrt/jrt.h @@ -227,57 +227,57 @@ inline void *operator new (size_t, void *where) } /* operator new */ /** - * Read data of specified type (T) from specified buffer + * Read data from a specified buffer. * * Note: * Offset is in-out and is incremented if the read operation completes successfully. * - * @return true, if read was successful, i.e. offset + sizeof (T) doesn't exceed buffer size, + * @return true, if read was successful, i.e. offset + data_size doesn't exceed buffer size, * false - otherwise. */ -template -bool __attr_always_inline___ +inline bool jrt_read_from_buffer_by_offset (const uint8_t *buffer_p, /**< buffer */ size_t buffer_size, /**< size of buffer */ size_t *in_out_buffer_offset_p, /**< in: offset to read from, * out: offset, incremented on sizeof (T) */ - T *out_data_p) /**< out: data */ + void *out_data_p, /**< out: data */ + size_t out_data_size) /**< size of the readable data */ { - if (*in_out_buffer_offset_p + sizeof (T) > buffer_size) + if (*in_out_buffer_offset_p + out_data_size > buffer_size) { return false; } - memcpy (out_data_p, buffer_p + *in_out_buffer_offset_p, sizeof (T)); - *in_out_buffer_offset_p += sizeof (T); + memcpy (out_data_p, buffer_p + *in_out_buffer_offset_p, out_data_size); + *in_out_buffer_offset_p += out_data_size; return true; } /* jrt_read_from_buffer_by_offset */ /** - * Write data of specified type (T) to specified buffer + * Write data to a specified buffer. * * Note: * Offset is in-out and is incremented if the write operation completes successfully. * - * @return true, if write was successful, i.e. offset + sizeof (T) doesn't exceed buffer size, + * @return true, if write was successful, i.e. offset + data_size doesn't exceed buffer size, * false - otherwise. */ -template -bool __attr_always_inline___ +inline bool jrt_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */ size_t buffer_size, /**< size of buffer */ size_t *in_out_buffer_offset_p, /**< in: offset to read from, * out: offset, incremented on sizeof (T) */ - T data) /**< data */ + void *data_p, /**< data */ + size_t data_size) /**< size of the writable data */ { - if (*in_out_buffer_offset_p + sizeof (T) > buffer_size) + if (*in_out_buffer_offset_p + data_size > buffer_size) { return false; } - memcpy (buffer_p + *in_out_buffer_offset_p, &data, sizeof (T)); - *in_out_buffer_offset_p += sizeof (T); + memcpy (buffer_p + *in_out_buffer_offset_p, data_p, data_size); + *in_out_buffer_offset_p += data_size; return true; } /* jrt_write_to_buffer_by_offset */ diff --git a/jerry-core/lit/lit-globals.h b/jerry-core/lit/lit-globals.h index d040234c4f..7f69786947 100644 --- a/jerry-core/lit/lit-globals.h +++ b/jerry-core/lit/lit-globals.h @@ -17,6 +17,7 @@ #define LIT_GLOBALS_H #include "jrt.h" +#include "rcs-cpointer.h" /** * ECMAScript standard defines terms "code unit" and "character" as 16-bit unsigned value @@ -123,6 +124,21 @@ typedef uint32_t lit_code_point_t; */ typedef uint8_t lit_string_hash_t; +/** + * Literal type + */ +typedef rcs_record_t *lit_literal_t; + +/** + * Compressed pointer type + */ +typedef rcs_cpointer_t lit_cpointer_t; + +/** + * Invalid literal + */ +#define NOT_A_LITERAL (rcs_cpointer_null_cp ()) + /** * ECMA string hash value length, in bits */ diff --git a/jerry-core/lit/lit-literal-storage.cpp b/jerry-core/lit/lit-literal-storage.cpp index edd1c9eecd..6dc2431f07 100644 --- a/jerry-core/lit/lit-literal-storage.cpp +++ b/jerry-core/lit/lit-literal-storage.cpp @@ -1,4 +1,5 @@ /* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,336 +14,86 @@ * limitations under the License. */ -#include "bytecode-data.h" -#include "ecma-helpers.h" -#include "jrt.h" #include "lit-literal-storage.h" -#include "lit-literal.h" -#include "lit-magic-strings.h" - -/** - * Literal storage - * As our libc library doesn't call constructors of static variables, lit_storage is initialized - * in lit_init function by placement new operator. - */ -lit_literal_storage_t lit_storage; - -/** - * Get pointer to the previous record inside the literal storage - * - * @return pointer to the previous record of NULL if this is the first record ('prev' field in the header) - */ -rcs_record_t * -lit_charset_record_t::get_prev () const -{ - rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this); - it.skip (RCS_DYN_STORAGE_LENGTH_UNIT); - cpointer_t cpointer; - cpointer.packed_value = it.read (); - - return cpointer_t::decompress (cpointer); -} /* lit_charset_record_t::get_prev */ - -/** - * Set the pointer to the previous record inside the literal storage (sets 'prev' field in the header) - */ -void -lit_charset_record_t::set_prev (rcs_record_t *prev_rec_p) /**< pointer to the record to set as previous */ -{ - rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this); - it.skip (RCS_DYN_STORAGE_LENGTH_UNIT); - - it.write (cpointer_t::compress (prev_rec_p).packed_value); -} /* lit_charset_record_t::set_prev */ - -/** - * Set the charset of the record - */ -void -lit_charset_record_t::set_charset (const lit_utf8_byte_t *str, /**< buffer containing characters to set */ - lit_utf8_size_t size) /**< size of the buffer in bytes */ -{ - JERRY_ASSERT (header_size () + size == get_size () - get_alignment_bytes_count ()); - - rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this); - it.skip (header_size ()); - - for (lit_utf8_size_t i = 0; i < get_length (); ++i) - { - it.write (str[i]); - it.skip (); - } -} /* lit_charset_record_t::set_charset */ - -/** - * Get the characters which are stored to the record - * - * @return number of code units written to the buffer - */ -lit_utf8_size_t -lit_charset_record_t::get_charset (lit_utf8_byte_t *buff, /**< output buffer */ - size_t size) /**< size of the output buffer in bytes */ -{ - JERRY_ASSERT (buff && size >= sizeof (lit_utf8_byte_t)); - - rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this); - it.skip (header_size ()); - lit_utf8_size_t len = get_length (); - lit_utf8_size_t i; - - for (i = 0; i < len && size > 0; ++i) - { - buff[i] = it.read (); - it.skip (); - size -= sizeof (lit_utf8_byte_t); - } - - return i; -} /* lit_charset_record_t::get_charset */ - -/** - * Compares characters from the record to the string - * - * @return 0 if strings are equal - * -1 if str_to_compare_with is greater - * 1 if str_to_compare_with is less - */ -int -lit_charset_record_t::compare_utf8 (const lit_utf8_byte_t *str_to_compare_with, /**< buffer with string to compare */ - lit_utf8_size_t str_size) /**< size of the string */ -{ - TODO ("Support utf-8 in comparison."); - size_t i; - - if (get_length () == 0) - { - if (str_to_compare_with != NULL) - { - return -1; - } - else - { - return 0; - } - } - - if (str_to_compare_with == NULL) - { - return 1; - } - - rcs_record_iterator_t it_this (&lit_storage, this); - - it_this.skip (header_size ()); - - for (i = 0; i < get_length () && i < str_size; i++) - { - lit_utf8_byte_t chr = it_this.read (); - - if (chr > str_to_compare_with[i]) - { - return 1; - } - else if (chr < str_to_compare_with[i]) - { - return -1; - } - - it_this.skip (); - } - - if (i < str_size) - { - return -1; - } - - return 0; -} /* lit_charset_record_t::compare_zt */ - -/** - * Compares two lit_charset_record_t records for equality - * - * @return true if strings inside records are equal - * false otherwise - */ -bool -lit_charset_record_t::is_equal (lit_charset_record_t *rec) /**< charset record to compare with */ -{ - if (get_length () != rec->get_length ()) - { - return false; - } - - rcs_record_iterator_t it_this (&lit_storage, this); - rcs_record_iterator_t it_record (&lit_storage, rec); - - it_this.skip (header_size ()); - it_record.skip (rec->header_size ()); - - for (lit_utf8_size_t i = 0; i < get_length (); i++) - { - if (it_this.read () != it_record.read ()) - { - return false; - } - - it_this.skip (); - it_record.skip (); - } - - return true; -} /* lit_charset_record_t::is_equal */ - -/** - * Compare this lit_charset_record_t record with string (which could contain '\0' characters) for equality - * - * @return true if compared instances are equal - * false otherwise - */ -bool -lit_charset_record_t::is_equal_utf8_string (const lit_utf8_byte_t *str, /**< string to compare with */ - lit_utf8_size_t str_size) /**< length of the string */ -{ - rcs_record_iterator_t it_this (&lit_storage, this); - - it_this.skip (header_size ()); - - for (lit_utf8_size_t i = 0; i < get_length () && i < str_size; i++) - { - if (it_this.read () != str[i]) - { - return false; - } - - it_this.skip (); - } - - return get_length () == str_size; -} /* lit_charset_record_t::equal_non_zt */ - -/** - * Dump charset record to specified snapshot buffer - * - * @return number of bytes dumped, - * or 0 - upon dump failure - */ -uint32_t -lit_charset_record_t::dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to */ - size_t buffer_size, /**< buffer size */ - size_t *in_out_buffer_offset_p) /**< in-out: buffer write offset */ -{ - lit_utf8_size_t length = get_length (); - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, length)) - { - return 0; - } - - rcs_record_iterator_t it_this (&lit_storage, this); - - it_this.skip (header_size ()); - - for (lit_utf8_size_t i = 0; i < length; i++) - { - lit_utf8_byte_t next_byte = it_this.read (); - it_this.skip (); - - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, next_byte)) - { - return 0; - } - } - - return ((uint32_t) sizeof (length) + length * (uint32_t) sizeof (lit_utf8_byte_t)); -} /* lit_charset_record_t::dump_for_snapshot */ - -/** - * Dump number record to specified snapshot buffer - * - * @return number of bytes dumped, - * or 0 - upon dump failure - */ -uint32_t -lit_number_record_t::dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to */ - size_t buffer_size, /**< buffer size */ - size_t *in_out_buffer_offset_p) const /**< in-out: buffer write offset */ -{ - /* dumping as double (not ecma_number_t), because ecma_number_t can be float or double, - * depending on engine compile-time configuration */ - double num = get_number (); - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, num)) - { - return 0; - } +#include "ecma-helpers.h" +#include "rcs-allocator.h" +#include "rcs-iterator.h" +#include "rcs-records.h" - return ((uint32_t) sizeof (num)); -} /* lit_number_record_t::dump_for_snapshot */ +rcs_record_set_t rcs_lit_storage; /** * Create charset record in the literal storage * - * @return pointer to the created record + * @return pointer to the created record */ -lit_charset_record_t * -lit_literal_storage_t::create_charset_record (const lit_utf8_byte_t *str, /**< string to be placed in the record */ - lit_utf8_size_t buf_size) /**< size in bytes of the buffer which holds the - * string */ +rcs_record_t * +lit_create_charset_literal (rcs_record_set_t *rec_set_p, /**< recordset */ + const lit_utf8_byte_t *str_p, /**< string to be placed into the record */ + const lit_utf8_size_t buf_size) /**< size in bytes of the buffer which holds the string */ { - const size_t alignment = lit_charset_record_t::size (buf_size) - (lit_charset_record_t::header_size () + buf_size); + const size_t record_size = RCS_CHARSET_HEADER_SIZE + buf_size; + const size_t aligned_record_size = JERRY_ALIGNUP (record_size, RCS_DYN_STORAGE_LENGTH_UNIT); + const size_t alignment = aligned_record_size - record_size; - lit_charset_record_t *ret = alloc_record (LIT_STR, buf_size); + rcs_record_t *rec_p = rcs_alloc_record (rec_set_p, RCS_RECORD_TYPE_CHARSET, aligned_record_size); - ret->set_alignment_bytes_count (alignment); - ret->set_charset (str, buf_size); - ret->set_hash (lit_utf8_string_calc_hash (str, ret->get_length ())); + rcs_record_set_alignment_bytes_count (rec_p, (uint8_t) alignment); + rcs_record_set_charset (rec_set_p, rec_p, str_p, buf_size); + rcs_record_set_hash (rec_p, lit_utf8_string_calc_hash (str_p, rcs_record_get_length (rec_p))); - return ret; -} /* lit_literal_storage_t::create_charset_record */ + return rec_p; +} /* lit_create_charset_literal */ /** - * Create magic string record in the literal storage + * Create magic string record in the literal storage. * * @return pointer to the created record */ -lit_magic_record_t * -lit_literal_storage_t::create_magic_record (lit_magic_string_id_t id) /**< id of a magic string */ +rcs_record_t * +lit_create_magic_literal (rcs_record_set_t *rec_set_p, /**< recordset */ + lit_magic_string_id_t id) /**< id of magic string */ { - lit_magic_record_t *ret = alloc_record (LIT_MAGIC_STR); - ret->set_magic_str_id (id); + rcs_record_t *rec_p = rcs_alloc_record (rec_set_p, RCS_RECORD_TYPE_MAGIC_STR, RCS_MAGIC_STR_HEADER_SIZE); + rcs_record_set_magic_str_id (rec_p, id); - return ret; -} /* lit_literal_storage_t::create_magic_record */ + return rec_p; +} /* lit_create_magic_literal */ /** - * Create external magic string record in the literal storage + * Create external magic string record in the literal storage. * * @return pointer to the created record */ -lit_magic_record_t * -lit_literal_storage_t::create_magic_record_ex (lit_magic_string_ex_id_t id) /**< id of a magic string */ +rcs_record_t * +lit_create_magic_literal_ex (rcs_record_set_t *rec_set_p, /**< recordset */ + lit_magic_string_ex_id_t id) /**< id of magic string */ { - lit_magic_record_t *ret = alloc_record (LIT_MAGIC_STR_EX); - ret->set_magic_str_id (id); + rcs_record_t *rec_p = rcs_alloc_record (rec_set_p, RCS_RECORD_TYPE_MAGIC_STR_EX, RCS_MAGIC_STR_HEADER_SIZE); + rcs_record_set_magic_str_ex_id (rec_p, id); - return ret; -} /* lit_literal_storage_t::create_magic_record_ex */ + return rec_p; +} /* lit_create_magic_record_ex */ /** - * Create number record in the literal storage + * Create number record in the literal storage. * * @return pointer to the created record */ -lit_number_record_t * -lit_literal_storage_t::create_number_record (ecma_number_t num) /**< number */ +rcs_record_t * +lit_create_number_literal (rcs_record_set_t *rec_set_p, /** recordset */ + ecma_number_t num) /**< numeric value */ { - lit_number_record_t *ret = alloc_record (LIT_NUMBER); - rcs_record_iterator_t it_this (this, ret); + const size_t record_size = RCS_NUMBER_HEADER_SIZE + sizeof (ecma_number_t); + rcs_record_t *rec_p = rcs_alloc_record (rec_set_p, RCS_RECORD_TYPE_NUMBER, record_size); - it_this.skip (ret->header_size ()); - it_this.write (num); + rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p); + rcs_iterator_skip (&it_ctx, RCS_NUMBER_HEADER_SIZE); + rcs_iterator_write (&it_ctx, &num, sizeof (ecma_number_t)); - return ret; -} /* lit_literal_storage_t::create_number_record */ + return rec_p; +} /* lit_create_number_literal */ /** * Count literal records in the storage @@ -350,77 +101,87 @@ lit_literal_storage_t::create_number_record (ecma_number_t num) /**< number */ * @return number of literals */ uint32_t -lit_literal_storage_t::count_literals (void) +lit_count_literals (rcs_record_set_t *rec_set_p) /**< recordset */ { uint32_t num = 0; + rcs_record_t *rec_p; - for (literal_t lit = lit_storage.get_first (); lit != NULL; lit = lit_storage.get_next (lit)) + for (rec_p = rcs_record_get_first (rec_set_p); + rec_p != NULL; + rec_p = rcs_record_get_next (rec_set_p, rec_p)) { - rcs_record_t::type_t type = lit->get_type (); - - if (type >= _first_type_id) + if (rcs_record_get_type (rec_p) >= RCS_RECORD_TYPE_FIRST) { num++; } } return num; -} /* lit_literal_storage_t::count_literals */ +} /* lit_count_literals */ /** - * Dump the contents of the literal storage + * Dump the contents of the literal storage. */ void -lit_literal_storage_t::dump () +lit_dump_literals (rcs_record_set_t *rec_set_p) /**< recordset */ { + rcs_record_t *rec_p; + printf ("LITERALS:\n"); - for (rcs_record_t *rec_p = lit_storage.get_first (); rec_p != NULL; rec_p = lit_storage.get_next (rec_p)) + for (rec_p = rcs_record_get_first (rec_set_p); + rec_p != NULL; + rec_p = rcs_record_get_next (rec_set_p, rec_p)) { printf ("%p ", rec_p); - printf ("[%3zu] ", get_record_size (rec_p)); + printf ("[%3zu] ", rcs_record_get_size (rec_p)); - switch (rec_p->get_type ()) + switch (rcs_record_get_type (rec_p)) { - case LIT_STR: + case RCS_RECORD_TYPE_CHARSET: { - lit_charset_record_t *lit_p = static_cast (rec_p); - rcs_record_iterator_t it_this (this, rec_p); + rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p); + rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE); - it_this.skip (lit_charset_record_t::header_size ()); + size_t str_len = rcs_record_get_length (rec_p); + size_t i; - for (size_t i = 0; i < lit_p->get_length (); ++i) + for (i = 0; i < str_len; ++i) { FIXME ("Support proper printing of characters which occupy more than one byte.") - printf ("%c", it_this.read ()); - it_this.skip (); + + lit_utf8_byte_t chr; + rcs_iterator_read (&it_ctx, &chr, sizeof (lit_utf8_byte_t)); + rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t)); + + printf ("%c", chr); } printf (" : STRING"); break; } - case LIT_MAGIC_STR: + case RCS_RECORD_TYPE_MAGIC_STR: { - lit_magic_string_id_t id = lit_magic_record_get_magic_str_id (rec_p); + lit_magic_string_id_t id = rcs_record_get_magic_str_id (rec_p); printf ("%s : MAGIC STRING", lit_get_magic_string_utf8 (id)); printf (" [id=%d] ", id); break; } - case LIT_MAGIC_STR_EX: + case RCS_RECORD_TYPE_MAGIC_STR_EX: { - lit_magic_string_ex_id_t id = lit_magic_record_ex_get_magic_str_id (rec_p); + lit_magic_string_ex_id_t id = rcs_record_get_magic_str_ex_id (rec_p); printf ("%s : EXT MAGIC STRING", lit_get_magic_string_ex_utf8 (id)); printf (" [id=%d] ", id); break; } - case LIT_NUMBER: + case RCS_RECORD_TYPE_NUMBER: { - lit_number_record_t *lit_p = static_cast (rec_p); + ecma_number_t value = rcs_record_get_number (rec_set_p, rec_p); - if (ecma_number_is_nan (lit_p->get_number ())) + if (ecma_number_is_nan (value)) { printf ("%s : NUMBER", "NaN"); } @@ -429,7 +190,7 @@ lit_literal_storage_t::dump () 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 (lit_p->get_number (), buff, 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); printf ("%s : NUMBER", buff); @@ -445,425 +206,4 @@ lit_literal_storage_t::dump () printf ("\n"); } -} /* lit_literal_storage_t::dump */ - -/** - * Get previous record in the literal storage - * - * @return pointer to the previous record relative to rec_p, or NULL if rec_p is the first record in the storage - */ -rcs_record_t * -lit_literal_storage_t::get_prev (rcs_record_t *rec_p) /**< record, relative to which previous should be found */ -{ - switch (rec_p->get_type ()) - { - case LIT_STR: - { - return (static_cast (rec_p))->get_prev (); - } - case LIT_MAGIC_STR: - case LIT_MAGIC_STR_EX: - { - return (static_cast (rec_p))->get_prev (); - } - case LIT_NUMBER: - { - return (static_cast (rec_p))->get_prev (); - } - default: - { - JERRY_ASSERT (rec_p->get_type () < _first_type_id); - - return rcs_recordset_t::get_prev (rec_p); - } - } -} /* lit_literal_storage_t::get_prev */ - -/** - * Set pointer to the previous record - */ -void -lit_literal_storage_t::set_prev (rcs_record_t *rec_p, /**< record to modify */ - rcs_record_t *prev_rec_p) /**< record which should be set as previous */ -{ - switch (rec_p->get_type ()) - { - case LIT_STR: - { - return (static_cast (rec_p))->set_prev (prev_rec_p); - } - case LIT_MAGIC_STR: - case LIT_MAGIC_STR_EX: - { - return (static_cast (rec_p))->set_prev (prev_rec_p); - } - case LIT_NUMBER: - { - return (static_cast (rec_p))->set_prev (prev_rec_p); - } - default: - { - JERRY_ASSERT (rec_p->get_type () < _first_type_id); - - return rcs_recordset_t::set_prev (rec_p, prev_rec_p); - } - } -} /* lit_literal_storage_t::set_prev */ - -/** - * Get size of a record - * - * @return size of a record in bytes - */ -size_t -lit_literal_storage_t::get_record_size (rcs_record_t* rec_p) /**< pointer to a record */ -{ - switch (rec_p->get_type ()) - { - case LIT_STR: - { - return (static_cast (rec_p))->get_size (); - } - case LIT_MAGIC_STR: - case LIT_MAGIC_STR_EX: - { - return lit_magic_record_t::size (); - } - case LIT_NUMBER: - { - return lit_number_record_t::size (); - } - default: - { - JERRY_ASSERT (rec_p->get_type () < _first_type_id); - - return rcs_recordset_t::get_record_size (rec_p); - } - } -} /* lit_literal_storage_t::get_record_size */ - -#ifdef JERRY_ENABLE_SNAPSHOT -/** - * Dump literals to specified snapshot buffer - * - * @return true, if dump was performed successfully (i.e. buffer size is sufficient), - * false - otherwise. - */ -bool -lit_dump_literals_for_snapshot (uint8_t *buffer_p, /**< output snapshot buffer */ - size_t buffer_size, /**< size of the buffer */ - size_t *in_out_buffer_offset_p, /**< in-out: write position in the buffer */ - lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< out: map from literal identifiers - * to the literal offsets - * in snapshot */ - - uint32_t *out_map_num_p, /**< out: number of literals */ - uint32_t *out_lit_table_size_p) /**< out: number of bytes, dumped to snapshot buffer */ -{ - uint32_t literals_num = lit_storage.count_literals (); - uint32_t lit_table_size = 0; - - *out_map_p = NULL; - *out_map_num_p = 0; - *out_lit_table_size_p = 0; - - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, literals_num)) - { - return false; - } - lit_table_size += (uint32_t) sizeof (literals_num); - - if (literals_num != 0) - { - bool is_ok = true; - - size_t id_map_size = sizeof (lit_mem_to_snapshot_id_map_entry_t) * literals_num; - lit_mem_to_snapshot_id_map_entry_t *id_map_p; - id_map_p = (lit_mem_to_snapshot_id_map_entry_t *) mem_heap_alloc_block (id_map_size, MEM_HEAP_ALLOC_SHORT_TERM); - - uint32_t literal_index = 0; - - 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_literal_storage_t::LIT_TYPE_FIRST - && type <= lit_literal_storage_t::LIT_TYPE_LAST)) - { - continue; - } - - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, type)) - { - is_ok = false; - break; - } - - uint32_t sz; - - if (type == LIT_STR_T) - { - lit_charset_record_t *rec_p = static_cast (lit); - - sz = rec_p->dump_for_snapshot (buffer_p, buffer_size, in_out_buffer_offset_p); - } - else if (type == LIT_MAGIC_STR_T - || type == LIT_MAGIC_STR_EX_T) - { - lit_magic_record_t *rec_p = static_cast (lit); - - if (type == LIT_MAGIC_STR_T) - { - sz = rec_p->dump_for_snapshot (buffer_p, buffer_size, in_out_buffer_offset_p); - } - else - { - JERRY_ASSERT (type == LIT_MAGIC_STR_EX_T); - - sz = rec_p->dump_for_snapshot (buffer_p, buffer_size, in_out_buffer_offset_p); - } - } - else - { - JERRY_ASSERT (type == LIT_NUMBER_T); - - lit_number_record_t *rec_p = static_cast (lit); - - sz = rec_p->dump_for_snapshot (buffer_p, buffer_size, in_out_buffer_offset_p); - } - - if (sz == 0) - { - /* write failed */ - is_ok = false; - break; - } - else - { - lit_cpointer_t lit_cp = lit_cpointer_t::compress (lit); - id_map_p[literal_index].literal_id = lit_cp; - id_map_p[literal_index].literal_offset = lit_table_size; - - lit_table_size += (uint32_t) sizeof (type); - lit_table_size += sz; - } - - literal_index++; - } - - if (!is_ok) - { - mem_heap_free_block (id_map_p); - - return false; - } - else - { - JERRY_ASSERT (literal_index == literals_num); - - *out_map_p = id_map_p; - } - } - - if (!bc_align_data_in_output_buffer (&lit_table_size, - buffer_p, - buffer_size, - in_out_buffer_offset_p)) - { - return false; - } - - *out_map_num_p = literals_num; - *out_lit_table_size_p = lit_table_size; - - return true; -} /* lit_dump_literals_for_snapshot */ - -/** - * Load literals from snapshot - * - * @return true, if load was performed successfully (i.e. literals dump in the snapshot is consistent), - * false - otherwise (i.e. snapshot is incorrect). - */ -bool -lit_load_literals_from_snapshot (const uint8_t *lit_table_p, /**< buffer with literal table in snapshot */ - uint32_t lit_table_size, /**< size of literal table in snapshot */ - lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< out: map from literal offsets - * in snapshot to identifiers - * of loaded literals in literal - * storage */ - uint32_t *out_map_num_p, /**< out: literals number */ - bool is_copy) /** flag, indicating whether the passed in-snapshot data - * should be copied to engine's memory (true), - * or it can be referenced until engine is stopped - * (i.e. until call to jerry_cleanup) */ -{ - /* currently, always performing literals copy */ - (void) is_copy; - - *out_map_p = NULL; - *out_map_num_p = 0; - - size_t lit_table_read = 0; - - uint32_t literals_num; - if (!jrt_read_from_buffer_by_offset (lit_table_p, - lit_table_size, - &lit_table_read, - &literals_num)) - { - return false; - } - - if (literals_num == 0) - { - return true; - } - - size_t id_map_size = sizeof (lit_mem_to_snapshot_id_map_entry_t) * literals_num; - lit_mem_to_snapshot_id_map_entry_t *id_map_p; - id_map_p = (lit_mem_to_snapshot_id_map_entry_t *) mem_heap_alloc_block (id_map_size, MEM_HEAP_ALLOC_SHORT_TERM); - - bool is_ok = true; - - for (uint32_t lit_index = 0; lit_index < literals_num; lit_index++) - { - uint32_t offset = (uint32_t) lit_table_read; - JERRY_ASSERT (offset == lit_table_read); - - rcs_record_t::type_t type; - if (!jrt_read_from_buffer_by_offset (lit_table_p, - lit_table_size, - &lit_table_read, - &type)) - { - is_ok = false; - break; - } - - literal_t lit; - - if (type == LIT_STR_T) - { - lit_utf8_size_t length; - if (!jrt_read_from_buffer_by_offset (lit_table_p, - lit_table_size, - &lit_table_read, - &length) - || (lit_table_read + length > lit_table_size)) - { - is_ok = false; - break; - } - - lit = lit_find_or_create_literal_from_utf8_string (lit_table_p + lit_table_read, length); - lit_table_read += length; - } - else if (type == LIT_MAGIC_STR_T) - { - lit_magic_string_id_t id; - if (!jrt_read_from_buffer_by_offset (lit_table_p, - lit_table_size, - &lit_table_read, - &id)) - { - is_ok = false; - break; - } - - const lit_utf8_byte_t *magic_str_p = lit_get_magic_string_utf8 (id); - lit_utf8_size_t magic_str_sz = lit_get_magic_string_size (id); - - /* - * TODO: - * Consider searching literal storage by magic string identifier instead of by its value - */ - lit = lit_find_or_create_literal_from_utf8_string (magic_str_p, magic_str_sz); - } - else if (type == LIT_MAGIC_STR_EX_T) - { - lit_magic_string_ex_id_t id; - if (!jrt_read_from_buffer_by_offset (lit_table_p, - lit_table_size, - &lit_table_read, - &id)) - { - is_ok = false; - break; - } - - const lit_utf8_byte_t *magic_str_ex_p = lit_get_magic_string_ex_utf8 (id); - lit_utf8_size_t magic_str_ex_sz = lit_get_magic_string_ex_size (id); - - /* - * TODO: - * Consider searching literal storage by magic string identifier instead of by its value - */ - lit = lit_find_or_create_literal_from_utf8_string (magic_str_ex_p, magic_str_ex_sz); - } - else if (type == LIT_NUMBER_T) - { - double num; - if (!jrt_read_from_buffer_by_offset (lit_table_p, - lit_table_size, - &lit_table_read, - &num)) - { - is_ok = false; - break; - } - - lit = lit_find_or_create_literal_from_num ((ecma_number_t) num); - } - else - { - is_ok = false; - break; - } - - id_map_p[lit_index].literal_offset = offset; - id_map_p[lit_index].literal_id = lit_cpointer_t::compress (lit); - } - - if (is_ok) - { - *out_map_p = id_map_p; - *out_map_num_p = literals_num; - - return true; - } - else - { - mem_heap_free_block (id_map_p); - - return false; - } -} /* lit_load_literals_from_snapshot */ -#endif /* JERRY_ENABLE_SNAPSHOT */ - -template void rcs_record_iterator_t::skip (); -template void rcs_record_iterator_t::skip (); -template void rcs_record_iterator_t::skip (); - -template void rcs_record_iterator_t::write (uint8_t); -template uint8_t rcs_record_iterator_t::read (); - -template void rcs_record_iterator_t::write (ecma_number_t); -template ecma_number_t rcs_record_iterator_t::read (); - -template void rcs_record_iterator_t::write (uint16_t); -template uint16_t rcs_record_iterator_t::read (); - -template lit_magic_string_id_t lit_magic_record_t::get_magic_str_id() const; -template lit_magic_string_ex_id_t lit_magic_record_t::get_magic_str_id() const; -template void lit_magic_record_t::set_magic_str_id(lit_magic_string_id_t); -template void lit_magic_record_t::set_magic_str_id(lit_magic_string_ex_id_t); -template uint32_t lit_magic_record_t::dump_for_snapshot(uint8_t *, size_t, size_t *) const; -template uint32_t lit_magic_record_t::dump_for_snapshot(uint8_t *, size_t, size_t *) const; - -template lit_charset_record_t *rcs_recordset_t::alloc_record (rcs_record_t::type_t type, - size_t size); -template lit_magic_record_t *rcs_recordset_t::alloc_record (rcs_record_t::type_t type); -template lit_number_record_t *rcs_recordset_t::alloc_record (rcs_record_t::type_t type); +} /* lit_dump_literals */ diff --git a/jerry-core/lit/lit-literal-storage.h b/jerry-core/lit/lit-literal-storage.h index cce8ad4973..7963551275 100644 --- a/jerry-core/lit/lit-literal-storage.h +++ b/jerry-core/lit/lit-literal-storage.h @@ -1,4 +1,5 @@ /* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,466 +18,15 @@ #define LIT_LITERAL_STORAGE_H #include "ecma-globals.h" -#include "rcs-recordset.h" -class lit_literal_storage_t; -extern lit_literal_storage_t lit_storage; +extern rcs_record_set_t rcs_lit_storage; -/** - * Charset record - * - * layout: - * ------- header ----------------------- - * type (4 bits) - * alignment (2 bits) - * unused (2 bits) - * hash (8 bits) - * length (16 bits) - * pointer to prev (16 bits) - * ------- characters ------------------- - * ... - * chars - * .... - * ------- alignment bytes -------------- - * unused bytes (their count is specified - * by 'alignment' field in header) - * -------------------------------------- - */ -class lit_charset_record_t : public rcs_record_t -{ - friend class rcs_recordset_t; - friend class lit_literal_storage_t; - -public: - /** - * Calculate the size that record will occupy inside the storage - * - * @return size of the record in bytes - */ - static size_t - size (size_t size) /**< size of the charset buffer */ - { - return JERRY_ALIGNUP (size + header_size (), RCS_DYN_STORAGE_LENGTH_UNIT); - } /* size */ - - /** - * Get the size of the header part of the record - * - * @return size of the header in bytes - */ - static size_t - header_size () - { - return _header_size; - } /* header_size */ - - /** - * Get the count of the alignment bytes at the end of record. - * These bytes are needed to align the record to RCS_DYN_STORAGE_ALIGNMENT. - * - * @return alignment bytes count (the value of the 'alignment' field in the header) - */ - size_t - get_alignment_bytes_count () const - { - return get_field (_alignment_field_pos, _alignment_field_width); - } /* get_alignment_bytes_count */ - - /** - * Set the count of the alignment bytes at the end of record (the value of the 'alignment' field in the header) - */ - void - set_alignment_bytes_count (size_t count) /**< count of the alignment bytes */ - { - JERRY_ASSERT (count <= RCS_DYN_STORAGE_LENGTH_UNIT); - set_field (_alignment_field_pos, _alignment_field_width, count); - } /* set_alignment_bytes_count */ - - /** - * Get hash value of the record's charset. - * - * @return hash value of the string (the value of the 'hash' field in the header) - */ - lit_string_hash_t - get_hash () const - { - return (lit_string_hash_t) get_field (_hash_field_pos, _hash_field_width); - } /* get_hash */ - - /** - * Get the length of the string, which is contained inside the record - * - * @return length of the string (bytes count) - */ - lit_utf8_size_t - get_length () const - { - return (lit_utf8_size_t) (get_size () - header_size () - get_alignment_bytes_count ()); - } /* get_length */ - - /** - * Get the size of the record - * - * @return size of the record in bytes - */ - size_t - get_size () const - { - return get_field (_length_field_pos, _length_field_width) * RCS_DYN_STORAGE_LENGTH_UNIT; - } /* get_size */ - - rcs_record_t *get_prev () const; - - lit_utf8_size_t get_charset (lit_utf8_byte_t *, size_t); - - int compare_utf8 (const lit_utf8_byte_t *, lit_utf8_size_t); - bool is_equal (lit_charset_record_t *); - bool is_equal_utf8_string (const lit_utf8_byte_t *, lit_utf8_size_t); - - uint32_t dump_for_snapshot (uint8_t *, size_t, size_t *); -private: - /** - * Set record's size (the value of the 'length' field in the header) - */ - void - set_size (size_t size) /**< size in bytes */ - { - JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size); - - set_field (_length_field_pos, _length_field_width, size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG); - } /* set_size */ - - /** - * Set record's hash (the value of the 'hash' field in the header) - */ - void - set_hash (lit_string_hash_t hash) /**< hash value */ - { - set_field (_hash_field_pos, _hash_field_width, hash); - } /* set_hash */ - - void set_prev (rcs_record_t *); - - void set_charset (const lit_utf8_byte_t *, lit_utf8_size_t); - - /** - * Offset and length of 'alignment' field, in bits - */ - static const uint32_t _alignment_field_pos = _fields_offset_begin; - static const uint32_t _alignment_field_width = RCS_DYN_STORAGE_LENGTH_UNIT_LOG; - - /** - * Offset and length of 'hash' field, in bits - */ - static const uint32_t _hash_field_pos = _alignment_field_pos + _alignment_field_width; - static const uint32_t _hash_field_width = 8u; - - /** - * Offset and length of 'alignment' field, in bits - */ - static const uint32_t _length_field_pos = _hash_field_pos + _hash_field_width; - static const uint32_t _length_field_width = 16u; - - /** - * Offset and length of 'prev' field, in bits - */ - static const uint32_t _prev_field_pos = _length_field_pos + _length_field_width; - static const uint32_t _prev_field_width = rcs_cpointer_t::bit_field_width; - - static const size_t _header_size = RCS_DYN_STORAGE_LENGTH_UNIT + RCS_DYN_STORAGE_LENGTH_UNIT / 2; -}; /* lit_charset_record_t */ - -/** - * Magic string record - * Doesn't hold any characters. Corresponding string is identified by its id. - * - * Layout: - * ------- header ----------------------- - * type (4 bits) - * magic string id (12 bits) - * pointer to prev (16 bits) - * -------------------------------------- - */ -class lit_magic_record_t : public rcs_record_t -{ - friend class rcs_recordset_t; - friend class lit_literal_storage_t; - -public: - /** - * Calculate the size that record will occupy inside the storage - * - * @return size of the record in bytes - */ - static size_t size () - { - return _size; - } /* size */ - - /** - * Get the size of the header part of the record - * - * @return size of the header in bytes - */ - static size_t header_size () - { - return _size; - } /* header_size */ - - /** - * Get the size of the record - * - * @return size of the record in bytes - */ - size_t get_size () const - { - return _size; - } /* get_size */ - - /** - * Get magic string id which is held by the record - * - * @return magic string id - */ - template - magic_string_id_t get_magic_str_id () const - { - uint32_t id = get_field (magic_field_pos, magic_field_width); - return (magic_string_id_t) id; - } /* get_magic_str_id */ - - /** - * Dump magic string record to specified snapshot buffer - * - * @return number of bytes dumped, - * or 0 - upon dump failure - */ - template - uint32_t dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to */ - size_t buffer_size, /**< buffer size */ - size_t *in_out_buffer_offset_p) const /**< in-out: buffer write offset */ - { - magic_string_id_t id = get_magic_str_id (); - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, id)) - { - return 0; - } - - return ((uint32_t) sizeof (id)); - } /* dump_for_snapshot */ -private: - /** - * Set record's size (the value of the 'length' field in the header) - */ - void set_size (size_t size) /**< size in bytes */ - { - JERRY_ASSERT (size == get_size ()); - } /* set_size */ - - template - void set_magic_str_id (magic_string_id_t id) - { - set_field (magic_field_pos, magic_field_width, id); - } /* set_magic_str_id */ - - /** - * Get previous record in the literal storage - * - * @return pointer to the previous record relative to this record, or NULL if this is the first record in the - * storage - */ - rcs_record_t *get_prev () const - { - return get_pointer (prev_field_pos, prev_field_width); - } /* get_prev */ - - /** - * Set the pointer to the previous record inside the literal storage (sets 'prev' field in the header) - */ - void set_prev (rcs_record_t *prev_rec_p) - { - set_pointer (prev_field_pos, prev_field_width, prev_rec_p); - } /* set_prev */ - - - /** - * Offset and length of 'magic string id' field, in bits - */ - static const uint32_t magic_field_pos = _fields_offset_begin; - static const uint32_t magic_field_width = 12u; - - /** - * Offset and length of 'prev' field, in bits - */ - static const uint32_t prev_field_pos = magic_field_pos + magic_field_width; - static const uint32_t prev_field_width = rcs_cpointer_t::bit_field_width; - - static const size_t _size = RCS_DYN_STORAGE_LENGTH_UNIT; -}; /* lit_magic_record_t */ - -/** - * Number record - * Doesn't hold any characters, holds a number. Numbers from source code are represented as number literals. - * - * Layout: - * ------- header ----------------------- - * type (4 bits) - * padding (12 bits) - * pointer to prev (16 bits) - * -------------------------------------- - * ecma_number_t - */ -class lit_number_record_t : public rcs_record_t -{ - friend class rcs_recordset_t; - friend class lit_literal_storage_t; - -public: - - static size_t - size () - { - return _size; - } /* size */ - - /** - * Get the size of the header part of the record - * - * @return size of the header in bytes - */ - static size_t - header_size () - { - return _header_size; - } /* header_size */ - - /** - * Get the size of the record - * - * @return size of the record in bytes - */ - size_t - get_size () const - { - return _size; - } /* get_size */ - - /** - * Get previous record in the literal storage - * - * @return pointer to the previous record relative to this record, or NULL if this is the first record in the - * storage - */ - rcs_record_t * - get_prev () const - { - return get_pointer (prev_field_pos, prev_field_width); - } /* get_prev */ - - /** - * Set the pointer to the previous record inside the literal storage (sets 'prev' field in the header) - */ - void - set_prev (rcs_record_t *prev_rec_p) - { - set_pointer (prev_field_pos, prev_field_width, prev_rec_p); - } /* set_prev */ - - /** - * Get the number which is held by the record - * - * @return number - */ - ecma_number_t - get_number () const - { - rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, - (rcs_record_t *)this); - it.skip (header_size ()); - - return it.read (); - } /* get_number */ - - uint32_t dump_for_snapshot (uint8_t *, size_t, size_t *) const; -private: - /** - * Set record's size (the value of the 'length' field in the header) - */ - void - set_size (size_t size) /**< size in bytes */ - { - JERRY_ASSERT (size == get_size ()); - } /* set_size */ - - /** - * Offset and length of 'prev' field, in bits - */ - static const uint32_t prev_field_pos = _fields_offset_begin + 12u; - static const uint32_t prev_field_width = rcs_cpointer_t::bit_field_width; - - static const size_t _header_size = RCS_DYN_STORAGE_LENGTH_UNIT; - static const size_t _size = _header_size + sizeof (ecma_number_t); -}; /* lit_number_record_t */ - -/** - * Literal storage - * - * Represents flexible storage for the literals. The following records could be created inside the storage: - * - charset literal (lit_charset_record_t) - * - magic string literal (lit_magic_record_t) - * - number literal (lit_number_record_t) - */ -class lit_literal_storage_t : public rcs_recordset_t -{ -public: - enum - { - LIT_TYPE_FIRST = _first_type_id, - - LIT_STR = LIT_TYPE_FIRST, - LIT_MAGIC_STR, - LIT_MAGIC_STR_EX, - LIT_NUMBER, - - LIT_TYPE_LAST = LIT_NUMBER - }; - - lit_charset_record_t *create_charset_record (const lit_utf8_byte_t *, lit_utf8_size_t); - lit_magic_record_t *create_magic_record (lit_magic_string_id_t); - lit_magic_record_t *create_magic_record_ex (lit_magic_string_ex_id_t); - lit_number_record_t *create_number_record (ecma_number_t); - - uint32_t count_literals (void); - - void dump (); - -private: - virtual rcs_record_t *get_prev (rcs_record_t *); - virtual void set_prev (rcs_record_t *, rcs_record_t *); - virtual size_t get_record_size (rcs_record_t *); -}; /* lit_literal_storage_t */ - -#define LIT_STR_T (lit_literal_storage_t::LIT_STR) -#define LIT_MAGIC_STR_T (lit_literal_storage_t::LIT_MAGIC_STR) -#define LIT_MAGIC_STR_EX_T (lit_literal_storage_t::LIT_MAGIC_STR_EX) -#define LIT_NUMBER_T (lit_literal_storage_t::LIT_NUMBER) - -#ifdef JERRY_ENABLE_SNAPSHOT -/** - * Map from literal identifiers to the literal offsets in snapshot (or reverse) - */ -typedef struct -{ - lit_cpointer_t literal_id; /**< identifier of literal in literal storage */ - uint32_t literal_offset; /**< offset of the literal in snapshot */ -} lit_mem_to_snapshot_id_map_entry_t; - -extern bool -lit_dump_literals_for_snapshot (uint8_t *, size_t, size_t *, lit_mem_to_snapshot_id_map_entry_t **, - uint32_t *, uint32_t *); -extern bool lit_load_literals_from_snapshot (const uint8_t *, uint32_t, lit_mem_to_snapshot_id_map_entry_t **, - uint32_t *, bool); -#endif /* JERRY_ENABLE_SNAPSHOT */ +extern rcs_record_t *lit_create_charset_literal (rcs_record_set_t *, const lit_utf8_byte_t *, lit_utf8_size_t); +extern rcs_record_t *lit_create_magic_literal (rcs_record_set_t *, lit_magic_string_id_t); +extern rcs_record_t *lit_create_magic_literal_ex (rcs_record_set_t *, lit_magic_string_ex_id_t); +extern rcs_record_t *lit_create_number_literal (rcs_record_set_t *, ecma_number_t); +extern uint32_t lit_count_literals (rcs_record_set_t *); +extern void lit_dump_literals (rcs_record_set_t *); -#endif /* LIT_LITERAL_STORAGE_H */ +#endif /* !LIT_LITERAL_STORAGE_H */ diff --git a/jerry-core/lit/lit-literal.cpp b/jerry-core/lit/lit-literal.cpp index eb0c1e9d92..a9e6db50d6 100644 --- a/jerry-core/lit/lit-literal.cpp +++ b/jerry-core/lit/lit-literal.cpp @@ -16,7 +16,10 @@ #include "lit-literal.h" #include "ecma-helpers.h" -#include "lit-magic-strings.h" +#include "rcs-allocator.h" +#include "rcs-records.h" +#include "rcs-iterator.h" +#include "lit-literal-storage.h" /** * Initialize literal storage @@ -24,8 +27,10 @@ void lit_init () { - new (&lit_storage) lit_literal_storage_t (); - lit_storage.init (); + JERRY_ASSERT (rcs_get_node_data_space_size () % RCS_DYN_STORAGE_LENGTH_UNIT == 0); + + rcs_lit_storage.init (); + lit_magic_strings_init (); lit_magic_strings_ex_init (); } /* lit_init */ @@ -36,8 +41,8 @@ lit_init () void lit_finalize () { - lit_storage.cleanup (); - lit_storage.finalize (); + rcs_lit_storage.cleanup (); + rcs_lit_storage.free (); } /* lit_finalize */ /** @@ -46,7 +51,7 @@ lit_finalize () void lit_dump_literals () { - lit_storage.dump (); + lit_dump_literals (&rcs_lit_storage); } /* lit_dump_literals */ /** @@ -55,44 +60,46 @@ lit_dump_literals () * * @return pointer to created record */ -literal_t +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); - for (lit_magic_string_id_t msi = (lit_magic_string_id_t) 0; - msi < LIT_MAGIC_STRING__COUNT; - msi = (lit_magic_string_id_t) (msi + 1)) + 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 (msi) != str_size) + 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 (msi), str_size)) + if (!strncmp ((const char *) str_p, (const char *) lit_get_magic_string_utf8 (m_str_id), str_size)) { - return lit_storage.create_magic_record (msi); + return lit_create_magic_literal (&rcs_lit_storage, m_str_id); } } - for (lit_magic_string_ex_id_t msi = (lit_magic_string_ex_id_t) 0; - msi < lit_get_magic_string_ex_count (); - msi = (lit_magic_string_ex_id_t) (msi + 1)) + 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 (msi) != str_size) + 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 (msi), str_size)) + if (!strncmp ((const char *) str_p, (const char *) lit_get_magic_string_ex_utf8 (m_str_ex_id), str_size)) { - return lit_storage.create_magic_record_ex (msi); + return lit_create_magic_literal_ex (&rcs_lit_storage, m_str_ex_id); } } - return lit_storage.create_charset_record (str_p, str_size); + return lit_create_charset_literal (&rcs_lit_storage, str_p, str_size); } /* lit_create_literal_from_utf8_string */ /** @@ -101,7 +108,7 @@ lit_create_literal_from_utf8_string (const lit_utf8_byte_t *str_p, /**< string t * * @return pointer to a literal or NULL if no corresponding literal exists */ -literal_t +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 */ { @@ -109,30 +116,34 @@ lit_find_literal_by_utf8_string (const lit_utf8_byte_t *str_p, /**< a string to lit_string_hash_t str_hash = lit_utf8_string_calc_hash (str_p, str_size); - for (literal_t lit = lit_storage.get_first (); lit != NULL; lit = lit_storage.get_next (lit)) + lit_literal_t lit; + + for (lit = rcs_record_get_first (&rcs_lit_storage); + lit != NULL; + lit = rcs_record_get_next (&rcs_lit_storage, lit)) { - rcs_record_t::type_t type = lit->get_type (); + rcs_record_type_t type = rcs_record_get_type (lit); - if (type == LIT_STR_T) + if (RCS_RECORD_TYPE_IS_CHARSET (type)) { - if (static_cast(lit)->get_hash () != str_hash) + if (rcs_record_get_hash (lit) != str_hash) { continue; } - if (static_cast(lit)->get_length () != str_size) + if (rcs_record_get_length (lit) != str_size) { continue; } - if (!static_cast(lit)->compare_utf8 (str_p, str_size)) + if (rcs_record_is_equal_charset (&rcs_lit_storage, lit, str_p, str_size)) { return lit; } } - else if (type == LIT_MAGIC_STR_T) + else if (RCS_RECORD_TYPE_IS_MAGIC_STR (type)) { - lit_magic_string_id_t magic_id = lit_magic_record_get_magic_str_id (lit); + lit_magic_string_id_t magic_id = rcs_record_get_magic_str_id (lit); 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) @@ -145,9 +156,9 @@ lit_find_literal_by_utf8_string (const lit_utf8_byte_t *str_p, /**< a string to return lit; } } - else if (type == LIT_MAGIC_STR_EX_T) + else if (RCS_RECORD_TYPE_IS_MAGIC_STR_EX (type)) { - lit_magic_string_ex_id_t magic_id = lit_magic_record_ex_get_magic_str_id (lit); + lit_magic_string_ex_id_t magic_id = rcs_record_get_magic_str_ex_id (lit); 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) @@ -171,11 +182,11 @@ lit_find_literal_by_utf8_string (const lit_utf8_byte_t *str_p, /**< a string to * * @return pointer to existing or newly created record */ -literal_t +lit_literal_t lit_find_or_create_literal_from_utf8_string (const lit_utf8_byte_t *str_p, /**< string, could be non-zero-terminated */ lit_utf8_size_t str_size) /**< length of the string */ { - literal_t lit = lit_find_literal_by_utf8_string (str_p, str_size); + lit_literal_t lit = lit_find_literal_by_utf8_string (str_p, str_size); if (lit == NULL) { @@ -191,10 +202,10 @@ lit_find_or_create_literal_from_utf8_string (const lit_utf8_byte_t *str_p, /**< * * @return pointer to a newly created record */ -literal_t +lit_literal_t lit_create_literal_from_num (ecma_number_t num) /**< number to initialize a new number literal */ { - return lit_storage.create_number_record (num); + return lit_create_number_literal (&rcs_lit_storage, num); } /* lit_create_literal_from_num */ /** @@ -202,10 +213,10 @@ lit_create_literal_from_num (ecma_number_t num) /**< number to initialize a new * * @return pointer to existing or a newly created record */ -literal_t +lit_literal_t lit_find_or_create_literal_from_num (ecma_number_t num) /**< number which a literal should contain */ { - literal_t lit = lit_find_literal_by_num (num); + lit_literal_t lit = lit_find_literal_by_num (num); if (lit == NULL) { @@ -220,19 +231,22 @@ lit_find_or_create_literal_from_num (ecma_number_t num) /**< number which a lite * * @return pointer to existing or null */ -literal_t +lit_literal_t lit_find_literal_by_num (ecma_number_t num) /**< a number to search for */ { - for (literal_t lit = lit_storage.get_first (); lit != NULL; lit = lit_storage.get_next (lit)) + lit_literal_t lit; + for (lit = rcs_record_get_first (&rcs_lit_storage); + lit != NULL; + lit = rcs_record_get_next (&rcs_lit_storage, lit)) { - rcs_record_t::type_t type = lit->get_type (); + rcs_record_type_t type = rcs_record_get_type (lit); - if (type != LIT_NUMBER_T) + if (!RCS_RECORD_TYPE_IS_NUMBER (type)) { continue; } - ecma_number_t lit_num = static_cast(lit)->get_number (); + ecma_number_t lit_num = rcs_record_get_number (&rcs_lit_storage, lit); if (lit_num == num) { @@ -250,39 +264,45 @@ lit_find_literal_by_num (ecma_number_t num) /**< a number to search for */ * false otherwise */ static bool -lit_literal_equal_charset_rec (literal_t lit, /**< literal to compare */ - lit_charset_record_t *record) /**< charset record to compare */ +lit_literal_equal_charset_rec (lit_literal_t lit, /**< literal to compare */ + lit_literal_t record) /**< charset record to compare */ { - switch (lit->get_type ()) + switch (rcs_record_get_type (lit)) { - case LIT_STR_T: + case RCS_RECORD_TYPE_CHARSET: { - return static_cast(lit)->is_equal (record); + return rcs_record_is_equal (&rcs_lit_storage, lit, record); } - case LIT_MAGIC_STR_T: + case RCS_RECORD_TYPE_MAGIC_STR: { - 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)); + lit_magic_string_id_t magic_string_id = rcs_record_get_magic_str_id (lit); + return rcs_record_is_equal_charset (&rcs_lit_storage, + record, + lit_get_magic_string_utf8 (magic_string_id), + lit_get_magic_string_size (magic_string_id)); } - case LIT_MAGIC_STR_EX_T: + case RCS_RECORD_TYPE_MAGIC_STR_EX: { - 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)); + lit_magic_string_ex_id_t magic_string_id = rcs_record_get_magic_str_ex_id (lit); + + return rcs_record_is_equal_charset (&rcs_lit_storage, + record, + lit_get_magic_string_ex_utf8 (magic_string_id), + lit_get_magic_string_ex_size (magic_string_id)); } - case LIT_NUMBER_T: + case RCS_RECORD_TYPE_NUMBER: { + ecma_number_t num = rcs_record_get_number (&rcs_lit_storage, lit); + lit_utf8_byte_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; - lit_utf8_size_t copied = ecma_number_to_utf8_string (static_cast(lit)->get_number (), - buff, - sizeof (buff)); + lit_utf8_size_t copied = ecma_number_to_utf8_string (num, buff, sizeof (buff)); - return record->is_equal_utf8_string (buff, copied); + return rcs_record_is_equal_charset (&rcs_lit_storage, record, buff, copied); } default: { JERRY_UNREACHABLE (); + return false; } } } /* lit_literal_equal_charset_rec */ @@ -294,32 +314,32 @@ lit_literal_equal_charset_rec (literal_t lit, /**< literal to com * false otherwise */ bool -lit_literal_equal_utf8 (literal_t lit, /**< literal to compare */ +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->get_type ()) + switch (rcs_record_get_type (lit)) { - case LIT_STR_T: + case RCS_RECORD_TYPE_CHARSET: { - return static_cast(lit)->is_equal_utf8_string (str_p, str_size); + return rcs_record_is_equal_charset (&rcs_lit_storage, lit, str_p, str_size); } - case LIT_MAGIC_STR_T: + case RCS_RECORD_TYPE_MAGIC_STR: { - lit_magic_string_id_t magic_id = lit_magic_record_get_magic_str_id (lit); + lit_magic_string_id_t magic_id = rcs_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: + case RCS_RECORD_TYPE_MAGIC_STR_EX: { - lit_magic_string_ex_id_t magic_id = lit_magic_record_ex_get_magic_str_id (lit); + lit_magic_string_ex_id_t magic_id = rcs_record_get_magic_str_ex_id (lit); return lit_compare_utf8_string_and_magic_string_ex (str_p, str_size, magic_id); } - case LIT_NUMBER_T: + case RCS_RECORD_TYPE_NUMBER: { + ecma_number_t num = rcs_record_get_number (&rcs_lit_storage, lit); + 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)->get_number (), - num_buf, - sizeof (num_buf)); + 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); } @@ -337,7 +357,7 @@ lit_literal_equal_utf8 (literal_t lit, /**< literal to compare */ * false otherwise */ bool -lit_literal_equal_num (literal_t lit, /**< literal to check */ +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]; @@ -353,32 +373,35 @@ lit_literal_equal_num (literal_t lit, /**< literal to check */ * false otherwise */ bool -lit_literal_equal (literal_t lit1, /**< first literal */ - literal_t lit2) /**< second literal */ +lit_literal_equal (lit_literal_t lit1, /**< first literal */ + lit_literal_t lit2) /**< second literal */ { - switch (lit2->get_type ()) + switch (rcs_record_get_type (lit2)) { - case lit_literal_storage_t::LIT_STR: + case RCS_RECORD_TYPE_CHARSET: { - return lit_literal_equal_charset_rec (lit1, static_cast(lit2)); + return lit_literal_equal_charset_rec (lit1, lit2); } - case lit_literal_storage_t::LIT_MAGIC_STR: + case RCS_RECORD_TYPE_MAGIC_STR: { - lit_magic_string_id_t magic_str_id = lit_magic_record_get_magic_str_id (lit2); + lit_magic_string_id_t magic_str_id = rcs_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: + case RCS_RECORD_TYPE_MAGIC_STR_EX: { - lit_magic_string_ex_id_t magic_str_ex_id = lit_magic_record_ex_get_magic_str_id (lit2); + lit_magic_string_ex_id_t magic_str_ex_id = rcs_record_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_literal_storage_t::LIT_NUMBER: + case RCS_RECORD_TYPE_NUMBER: { - return lit_literal_equal_num (lit1, static_cast(lit2)->get_number ()); + ecma_number_t num = rcs_record_get_number (&rcs_lit_storage, lit2); + return lit_literal_equal_num (lit1, num); } default: { @@ -395,13 +418,13 @@ lit_literal_equal (literal_t lit1, /**< first literal */ * false otherwise */ bool -lit_literal_equal_type_utf8 (literal_t lit, /**< literal to compare */ +lit_literal_equal_type_utf8 (lit_literal_t lit, /**< literal to compare */ const lit_utf8_byte_t *str_p, /**< utf-8 string */ lit_utf8_size_t str_size) /**< string size */ { - if (lit->get_type () != LIT_STR_T - && lit->get_type () != LIT_MAGIC_STR_T - && lit->get_type () != LIT_MAGIC_STR_EX_T) + rcs_record_type_t type = rcs_record_get_type (lit); + + if (RCS_RECORD_TYPE_IS_NUMBER (type) || RCS_RECORD_TYPE_IS_FREE (type)) { return false; } @@ -417,7 +440,7 @@ lit_literal_equal_type_utf8 (literal_t lit, /**< literal to compare */ * false otherwise */ bool -lit_literal_equal_type_cstr (literal_t lit, /**< literal to compare */ +lit_literal_equal_type_cstr (lit_literal_t lit, /**< literal to compare */ const char *c_str_p) /**< zero-terminated C-string */ { return lit_literal_equal_type_utf8 (lit, (const lit_utf8_byte_t *) c_str_p, (lit_utf8_size_t) strlen (c_str_p)); @@ -431,10 +454,10 @@ lit_literal_equal_type_cstr (literal_t lit, /**< literal to compare */ * false otherwise */ bool -lit_literal_equal_type_num (literal_t lit, /**< literal to check */ +lit_literal_equal_type_num (lit_literal_t lit, /**< literal to check */ ecma_number_t num) /**< number to compare with */ { - if (lit->get_type () != lit_literal_storage_t::LIT_NUMBER) + if (!RCS_RECORD_IS_NUMBER (lit)) { return false; } @@ -450,10 +473,10 @@ lit_literal_equal_type_num (literal_t lit, /**< literal to check */ * false otherwise */ bool -lit_literal_equal_type (literal_t lit1, /**< first literal */ - literal_t lit2) /**< second literal */ +lit_literal_equal_type (lit_literal_t lit1, /**< first literal */ + lit_literal_t lit2) /**< second literal */ { - if (lit1->get_type () != lit2->get_type ()) + if (rcs_record_get_type (lit1) != rcs_record_get_type (lit2)) { return false; } @@ -461,7 +484,6 @@ lit_literal_equal_type (literal_t lit1, /**< first literal */ return lit_literal_equal (lit1, lit2); } /* lit_literal_equal_type */ - /** * 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, @@ -470,39 +492,34 @@ lit_literal_equal_type (literal_t lit1, /**< first literal */ * @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_literal_to_utf8_string (lit_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 (); + rcs_record_type_t type = rcs_record_get_type (lit); - switch (type) + if (RCS_RECORD_TYPE_IS_CHARSET (type)) { - case LIT_STR_T: - { - lit_charset_record_t *ch_rec_p = static_cast (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)->get_number (), buff_p, (ssize_t)size); - - return buff_p; - } - default: JERRY_UNREACHABLE (); + rcs_record_get_charset (&rcs_lit_storage, lit, buff_p, size); + return buff_p; + } + else if (RCS_RECORD_TYPE_IS_MAGIC_STR (type)) + { + return lit_get_magic_string_utf8 (rcs_record_get_magic_str_id (lit)); + } + else if (RCS_RECORD_TYPE_IS_MAGIC_STR_EX (type)) + { + return lit_get_magic_string_ex_utf8 (rcs_record_get_magic_str_ex_id (lit)); } + else + { + JERRY_ASSERT (RCS_RECORD_TYPE_IS_NUMBER (type)); - JERRY_UNREACHABLE (); + ecma_number_t number = rcs_record_get_number (&rcs_lit_storage, lit); + ecma_number_to_utf8_string (number, buff_p, (ssize_t) size); + return buff_p; + } } /* lit_literal_to_utf8_string */ /** @@ -512,7 +529,7 @@ lit_literal_to_utf8_string (literal_t lit, /**< literal to be processed */ * @return pointer to the C string. */ const char * -lit_literal_to_str_internal_buf (literal_t lit) /**< literal */ +lit_literal_to_str_internal_buf (lit_literal_t lit) /**< literal */ { static lit_utf8_byte_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER + 1]; memset (buff, 0, sizeof (buff)); @@ -528,11 +545,15 @@ lit_literal_to_str_internal_buf (literal_t lit) /**< literal */ * false otherwise */ static bool -lit_literal_exists (literal_t lit) /**< literal to check for existence */ +lit_literal_exists (lit_literal_t lit) /**< literal to check for existence */ { - for (literal_t l = lit_storage.get_first (); l != NULL; l = lit_storage.get_next (l)) + lit_literal_t current_lit; + + for (current_lit = rcs_record_get_first (&rcs_lit_storage); + current_lit != NULL; + current_lit = rcs_record_get_next (&rcs_lit_storage, current_lit)) { - if (l == lit) + if (current_lit == lit) { return true; } @@ -546,39 +567,39 @@ lit_literal_exists (literal_t lit) /**< literal to check for existence */ * * @return literal */ -literal_t -lit_get_literal_by_cp (lit_cpointer_t lit_cp) /**< compressed pointer to literal */ +lit_literal_t +lit_get_literal_by_cp (rcs_cpointer_t lit_cp) /**< compressed pointer to literal */ { JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL); - literal_t lit = lit_cpointer_t::decompress (lit_cp); + lit_literal_t lit = rcs_cpointer_decompress (lit_cp); JERRY_ASSERT (lit_literal_exists (lit)); return lit; } /* lit_get_literal_by_cp */ lit_string_hash_t -lit_charset_literal_get_hash (literal_t lit) /**< literal */ +lit_charset_literal_get_hash (lit_literal_t lit) /**< literal */ { - return static_cast (lit)->get_hash (); + return rcs_record_get_hash (lit); } /* lit_charset_literal_get_hash */ lit_magic_string_id_t -lit_magic_record_get_magic_str_id (literal_t lit) /**< literal */ +lit_magic_literal_get_magic_str_id (lit_literal_t lit) /**< literal */ { - return static_cast (lit)->get_magic_str_id (); -} /* lit_magic_record_get_magic_str_id */ + return rcs_record_get_magic_str_id (lit); +} /* lit_magic_literal_get_magic_str_id */ lit_magic_string_ex_id_t -lit_magic_record_ex_get_magic_str_id (literal_t lit) /**< literal */ +lit_magic_literal_ex_get_magic_str_id (lit_literal_t lit) /**< literal */ { - return static_cast (lit)->get_magic_str_id (); -} /* lit_magic_record_ex_get_magic_str_id */ + return rcs_record_get_magic_str_ex_id (lit); +} /* lit_magic_literal_ex_get_magic_str_id */ lit_utf8_size_t -lit_charset_record_get_size (literal_t lit) /**< literal */ +lit_charset_literal_get_size (lit_literal_t lit) /**< literal */ { - return static_cast (lit)->get_length (); -} /* lit_charset_record_get_size */ + return rcs_record_get_length (lit); +} /* lit_charset_literal_get_size */ /** * Get length of the literal @@ -586,36 +607,40 @@ lit_charset_record_get_size (literal_t lit) /**< literal */ * @return code units count */ ecma_length_t -lit_charset_record_get_length (literal_t lit) /**< literal */ +lit_charset_literal_get_length (lit_literal_t lit) /**< literal */ { TODO ("Add special case for literals which doesn't contain long characters"); - lit_charset_record_t *charset_record_p = static_cast (lit); - rcs_record_iterator_t lit_iter (&lit_storage, lit); - lit_iter.skip (lit_charset_record_t::header_size ()); + rcs_iterator_t it_ctx = rcs_iterator_create (&rcs_lit_storage, lit); + rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE); - lit_utf8_size_t lit_utf8_str_size = charset_record_p->get_length (); + lit_utf8_size_t lit_utf8_str_size = rcs_record_get_length (lit); ecma_length_t length = 0; - for (lit_utf8_size_t i = 0; i < lit_utf8_str_size;) + lit_utf8_size_t i = 0; + + while (i < lit_utf8_str_size) { - lit_utf8_byte_t byte = lit_iter.read (); - lit_utf8_size_t bytes_to_skip = lit_get_unicode_char_size_by_utf8_first_byte (byte); - lit_iter.skip (bytes_to_skip); - i += bytes_to_skip; + lit_utf8_byte_t byte; + lit_utf8_size_t bytes_to_skip; + + rcs_iterator_read (&it_ctx, &byte, sizeof (lit_utf8_byte_t)); + bytes_to_skip = lit_get_unicode_char_size_by_utf8_first_byte (byte); + rcs_iterator_skip (&it_ctx, bytes_to_skip); + i += bytes_to_skip; length += (bytes_to_skip > LIT_UTF8_MAX_BYTES_IN_CODE_UNIT) ? 2 : 1; } #ifndef JERRY_NDEBUG - lit_iter.skip (charset_record_p->get_alignment_bytes_count ()); - JERRY_ASSERT (lit_iter.finished ()); + rcs_iterator_skip (&it_ctx, rcs_record_get_alignment_bytes_count (lit)); + JERRY_ASSERT (rcs_iterator_finished (&it_ctx)); #endif return length; -} /* lit_charset_record_get_length */ +} /* lit_charset_literal_get_length */ ecma_number_t -lit_charset_literal_get_number (literal_t lit) /**< literal */ +lit_number_literal_get_number (lit_literal_t lit) /**< literal */ { - return static_cast (lit)->get_number ();; -} /* lit_charset_literal_get_number */ + return rcs_record_get_number (&rcs_lit_storage, lit); +} /* lit_number_literal_get_number */ diff --git a/jerry-core/lit/lit-literal.h b/jerry-core/lit/lit-literal.h index a52060d89d..e03efb76f6 100644 --- a/jerry-core/lit/lit-literal.h +++ b/jerry-core/lit/lit-literal.h @@ -16,42 +16,40 @@ #ifndef LIT_LITERAL_H #define LIT_LITERAL_H -#include "lit-globals.h" -#include "lit-literal-storage.h" -#include "lit-magic-strings.h" +#include "ecma-globals.h" -void lit_init (); -void lit_finalize (); -void lit_dump_literals (); +extern void lit_init (); +extern void lit_finalize (); +extern void lit_dump_literals (); -literal_t lit_create_literal_from_utf8_string (const lit_utf8_byte_t *, lit_utf8_size_t); -literal_t lit_find_literal_by_utf8_string (const lit_utf8_byte_t *, lit_utf8_size_t); -literal_t lit_find_or_create_literal_from_utf8_string (const lit_utf8_byte_t *, lit_utf8_size_t); +extern lit_literal_t lit_create_literal_from_utf8_string (const lit_utf8_byte_t *, lit_utf8_size_t); +extern lit_literal_t lit_find_literal_by_utf8_string (const lit_utf8_byte_t *, lit_utf8_size_t); +extern lit_literal_t lit_find_or_create_literal_from_utf8_string (const lit_utf8_byte_t *, lit_utf8_size_t); -literal_t lit_create_literal_from_num (ecma_number_t); -literal_t lit_find_literal_by_num (ecma_number_t); -literal_t lit_find_or_create_literal_from_num (ecma_number_t); +extern lit_literal_t lit_create_literal_from_num (ecma_number_t); +extern lit_literal_t lit_find_literal_by_num (ecma_number_t); +extern lit_literal_t lit_find_or_create_literal_from_num (ecma_number_t); -bool lit_literal_equal_utf8 (literal_t, const lit_utf8_byte_t *, lit_utf8_size_t); -bool lit_literal_equal_num (literal_t, ecma_number_t); -bool lit_literal_equal (literal_t, literal_t); +extern bool lit_literal_equal_utf8 (lit_literal_t, const lit_utf8_byte_t *, lit_utf8_size_t); +extern bool lit_literal_equal_num (lit_literal_t, ecma_number_t); +extern bool lit_literal_equal (lit_literal_t, lit_literal_t); -bool lit_literal_equal_type_utf8 (literal_t, const lit_utf8_byte_t *, lit_utf8_size_t); -bool lit_literal_equal_type_cstr (literal_t, const char *); -bool lit_literal_equal_type_num (literal_t, ecma_number_t); -bool lit_literal_equal_type (literal_t, literal_t); +extern bool lit_literal_equal_type_utf8 (lit_literal_t, const lit_utf8_byte_t *, lit_utf8_size_t); +extern bool lit_literal_equal_type_cstr (lit_literal_t, const char *); +extern bool lit_literal_equal_type_num (lit_literal_t, ecma_number_t); +extern bool lit_literal_equal_type (lit_literal_t, lit_literal_t); -const lit_utf8_byte_t *lit_literal_to_utf8_string (literal_t, lit_utf8_byte_t *, size_t); -const char *lit_literal_to_str_internal_buf (literal_t); +extern const lit_utf8_byte_t *lit_literal_to_utf8_string (lit_literal_t, lit_utf8_byte_t *, size_t); +extern const char *lit_literal_to_str_internal_buf (lit_literal_t); -literal_t lit_get_literal_by_cp (lit_cpointer_t); +extern lit_literal_t lit_get_literal_by_cp (lit_cpointer_t); -lit_string_hash_t lit_charset_literal_get_hash (literal_t); -ecma_number_t lit_charset_literal_get_number (literal_t); -lit_utf8_size_t lit_charset_record_get_size (literal_t); -ecma_length_t lit_charset_record_get_length (literal_t); +extern ecma_number_t lit_number_literal_get_number (lit_literal_t); +extern lit_string_hash_t lit_charset_literal_get_hash (lit_literal_t); +extern lit_utf8_size_t lit_charset_literal_get_size (lit_literal_t); +extern ecma_length_t lit_charset_literal_get_length (lit_literal_t); -lit_magic_string_id_t lit_magic_record_get_magic_str_id (literal_t); -lit_magic_string_ex_id_t lit_magic_record_ex_get_magic_str_id (literal_t); +extern lit_magic_string_id_t lit_magic_literal_get_magic_str_id (lit_literal_t); +extern lit_magic_string_ex_id_t lit_magic_literal_ex_get_magic_str_id (lit_literal_t); #endif /* LIT_LITERAL_H */ diff --git a/jerry-core/lit/lit-snapshot.cpp b/jerry-core/lit/lit-snapshot.cpp new file mode 100644 index 0000000000..7adb3ff050 --- /dev/null +++ b/jerry-core/lit/lit-snapshot.cpp @@ -0,0 +1,411 @@ + /* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lit-snapshot.h" + +#include "lit-literal.h" +#include "lit-literal-storage.h" +#include "rcs-allocator.h" +#include "rcs-iterator.h" +#include "rcs-records.h" + +#ifdef JERRY_ENABLE_SNAPSHOT + +/** + * Dump a record to specified snapshot buffer. + * + * @return number of bytes dumped, + * or 0 - upon dump failure + */ +static uint32_t +lit_snapshot_dump (lit_literal_t lit, /**< literal to dump */ + uint8_t *buffer_p, /**< buffer to dump to */ + size_t buffer_size, /**< buffer size */ + size_t *in_out_buffer_offset_p) /**< in-out: buffer write offset */ +{ + rcs_record_type_t record_type = rcs_record_get_type (lit); + + if (RCS_RECORD_TYPE_IS_NUMBER (record_type)) + { + double num_value = rcs_record_get_number (&rcs_lit_storage, lit); + size_t size = sizeof (num_value); + + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &num_value, + size)) + { + return 0; + } + + return (uint32_t) size; + } + + if (RCS_RECORD_TYPE_IS_CHARSET (record_type)) + { + lit_utf8_size_t length = rcs_record_get_length (lit); + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &length, + sizeof (length))) + { + return 0; + } + + rcs_iterator_t it_ctx = rcs_iterator_create (&rcs_lit_storage, lit); + rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE); + + lit_utf8_size_t i; + for (i = 0; i < length; ++i) + { + lit_utf8_byte_t next_byte; + rcs_iterator_read (&it_ctx, &next_byte, sizeof (lit_utf8_byte_t)); + + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &next_byte, + sizeof (next_byte))) + { + return 0; + } + + rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t)); + } + + return (uint32_t) (sizeof (uint32_t) + length * sizeof (uint8_t)); + } + + if (RCS_RECORD_TYPE_IS_MAGIC_STR (record_type)) + { + lit_magic_string_id_t id = rcs_record_get_magic_str_id (lit); + + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &id, + sizeof (id))) + { + return 0; + } + + return (uint32_t) sizeof (lit_magic_string_id_t); + } + + if (RCS_RECORD_TYPE_IS_MAGIC_STR_EX (record_type)) + { + lit_magic_string_ex_id_t id = rcs_record_get_magic_str_ex_id (lit); + + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &id, + sizeof (id))) + { + return 0; + } + + return (uint32_t) sizeof (lit_magic_string_ex_id_t); + } + + JERRY_UNREACHABLE (); + return 0; +} /* rcs_snapshot_dump */ + +/** + * Dump literals to specified snapshot buffer. + * + * @return true, if dump was performed successfully (i.e. buffer size is sufficient), + * false - otherwise. + */ +bool +lit_dump_literals_for_snapshot (uint8_t *buffer_p, /**< output snapshot buffer */ + size_t buffer_size, /**< size of the buffer */ + size_t *in_out_buffer_offset_p, /**< in-out: write position in the buffer */ + lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< out: map from literal identifiers + * to the literal offsets + * in snapshot */ + uint32_t *out_map_num_p, /**< out: number of literals */ + uint32_t *out_lit_table_size_p) /**< out: number of bytes, dumped to snapshot buffer */ +{ + uint32_t literals_num = lit_count_literals (&rcs_lit_storage); + uint32_t lit_table_size = 0; + + *out_map_p = NULL; + *out_map_num_p = 0; + *out_lit_table_size_p = 0; + + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &literals_num, + sizeof (literals_num))) + { + return false; + } + + lit_table_size += (uint32_t) sizeof (literals_num); + + if (literals_num != 0) + { + bool is_ok = true; + + size_t id_map_size = sizeof (lit_mem_to_snapshot_id_map_entry_t) * literals_num; + lit_mem_to_snapshot_id_map_entry_t *id_map_p; + id_map_p = (lit_mem_to_snapshot_id_map_entry_t *) mem_heap_alloc_block (id_map_size, MEM_HEAP_ALLOC_SHORT_TERM); + + uint32_t literal_index = 0; + lit_literal_t lit; + + for (lit = rcs_record_get_first (&rcs_lit_storage); + lit != NULL; + lit = rcs_record_get_next (&rcs_lit_storage, lit)) + { + rcs_record_type_t record_type = rcs_record_get_type (lit); + + if (RCS_RECORD_TYPE_IS_FREE (record_type)) + { + continue; + } + + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &record_type, + sizeof (record_type))) + { + is_ok = false; + break; + } + + uint32_t bytes = lit_snapshot_dump (lit, buffer_p, buffer_size, in_out_buffer_offset_p); + + if (bytes == 0) + { + /* write failed */ + is_ok = false; + break; + } + + rcs_cpointer_t lit_cp = rcs_cpointer_compress (lit); + id_map_p[literal_index].literal_id = lit_cp; + id_map_p[literal_index].literal_offset = lit_table_size; + + lit_table_size += (uint32_t) sizeof (record_type); + lit_table_size += bytes; + + literal_index++; + } + + if (!is_ok) + { + mem_heap_free_block (id_map_p); + return false; + } + + JERRY_ASSERT (literal_index == literals_num); + *out_map_p = id_map_p; + } + + uint32_t aligned_size = JERRY_ALIGNUP (lit_table_size, MEM_ALIGNMENT); + + if (aligned_size != lit_table_size) + { + JERRY_ASSERT (aligned_size > lit_table_size); + + uint8_t padding = 0; + uint32_t padding_bytes_num = (uint32_t) (aligned_size - lit_table_size); + uint32_t i; + + for (i = 0; i < padding_bytes_num; i++) + { + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &padding, + sizeof (uint8_t))) + { + return false; + } + } + } + + *out_map_num_p = literals_num; + *out_lit_table_size_p = aligned_size; + return true; +} /* lit_dump_literals_for_snapshot */ + +/** + * Load literals from snapshot. + * + * @return true, if load was performed successfully (i.e. literals dump in the snapshot is consistent), + * false - otherwise (i.e. snapshot is incorrect). + */ +bool +lit_load_literals_from_snapshot (const uint8_t *lit_table_p, /**< buffer with literal table in snapshot */ + uint32_t lit_table_size, /**< size of literal table in snapshot */ + lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< out: map from literal offsets + * in snapshot to identifiers + * of loaded literals in literal + * storage */ + uint32_t *out_map_num_p) /**< out: literals number */ +{ + *out_map_p = NULL; + *out_map_num_p = 0; + + size_t lit_table_read = 0; + + uint32_t literals_num; + if (!jrt_read_from_buffer_by_offset (lit_table_p, + lit_table_size, + &lit_table_read, + &literals_num, + sizeof (literals_num))) + { + return false; + } + + if (literals_num == 0) + { + return true; + } + + size_t id_map_size = sizeof (lit_mem_to_snapshot_id_map_entry_t) * literals_num; + lit_mem_to_snapshot_id_map_entry_t *id_map_p; + id_map_p = (lit_mem_to_snapshot_id_map_entry_t *) mem_heap_alloc_block (id_map_size, MEM_HEAP_ALLOC_SHORT_TERM); + + bool is_ok = true; + uint32_t lit_index; + + for (lit_index = 0; lit_index < literals_num; ++lit_index) + { + uint32_t offset = (uint32_t) lit_table_read; + JERRY_ASSERT (offset == lit_table_read); + + rcs_record_type_t type; + if (!jrt_read_from_buffer_by_offset (lit_table_p, + lit_table_size, + &lit_table_read, + &type, + sizeof (type))) + { + is_ok = false; + break; + } + + lit_literal_t lit; + + if (RCS_RECORD_TYPE_IS_CHARSET (type)) + { + lit_utf8_size_t length; + if (!jrt_read_from_buffer_by_offset (lit_table_p, + lit_table_size, + &lit_table_read, + &length, + sizeof (length)) + || (lit_table_read + length > lit_table_size)) + { + is_ok = false; + break; + } + + lit = (lit_literal_t) lit_find_or_create_literal_from_utf8_string (lit_table_p + lit_table_read, length); + lit_table_read += length; + } + else if (RCS_RECORD_TYPE_IS_MAGIC_STR (type)) + { + lit_magic_string_id_t id; + if (!jrt_read_from_buffer_by_offset (lit_table_p, + lit_table_size, + &lit_table_read, + &id, + sizeof (id))) + { + is_ok = false; + break; + } + + const lit_utf8_byte_t *magic_str_p = lit_get_magic_string_utf8 (id); + lit_utf8_size_t magic_str_sz = lit_get_magic_string_size (id); + + /* + * TODO: + * Consider searching literal storage by magic string identifier instead of by its value + */ + lit = (lit_literal_t) lit_find_or_create_literal_from_utf8_string (magic_str_p, magic_str_sz); + } + else if (RCS_RECORD_TYPE_IS_MAGIC_STR_EX (type)) + { + lit_magic_string_ex_id_t id; + if (!jrt_read_from_buffer_by_offset (lit_table_p, + lit_table_size, + &lit_table_read, + &id, + sizeof (id))) + { + is_ok = false; + break; + } + + const lit_utf8_byte_t *magic_str_ex_p = lit_get_magic_string_ex_utf8 (id); + lit_utf8_size_t magic_str_ex_sz = lit_get_magic_string_ex_size (id); + + /* + * TODO: + * Consider searching literal storage by magic string identifier instead of by its value + */ + lit = (lit_literal_t) lit_find_or_create_literal_from_utf8_string (magic_str_ex_p, magic_str_ex_sz); + } + else if (RCS_RECORD_TYPE_IS_NUMBER (type)) + { + double num; + if (!jrt_read_from_buffer_by_offset (lit_table_p, + lit_table_size, + &lit_table_read, + &num, + sizeof (num))) + { + is_ok = false; + break; + } + + lit = (lit_literal_t) lit_find_or_create_literal_from_num ((ecma_number_t) num); + } + else + { + is_ok = false; + break; + } + + id_map_p[lit_index].literal_offset = offset; + id_map_p[lit_index].literal_id = rcs_cpointer_compress (lit); + } + + if (is_ok) + { + *out_map_p = id_map_p; + *out_map_num_p = literals_num; + + return true; + } + + mem_heap_free_block (id_map_p); + return false; +} /* rcs_load_literals_from_snapshot */ + +#endif /* JERRY_ENABLE_SNAPSHOT */ diff --git a/jerry-core/lit/lit-snapshot.h b/jerry-core/lit/lit-snapshot.h new file mode 100644 index 0000000000..ca466f1bb8 --- /dev/null +++ b/jerry-core/lit/lit-snapshot.h @@ -0,0 +1,44 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RCS_SNAPSHOT_H +#define RCS_SNAPSHOT_H + +#include "rcs-cpointer.h" + +typedef struct +{ + rcs_cpointer_t literal_id; + uint32_t literal_offset; +} lit_mem_to_snapshot_id_map_entry_t; + +#ifdef JERRY_ENABLE_SNAPSHOT +extern bool +lit_dump_literals_for_snapshot (uint8_t *, + size_t, + size_t *, + lit_mem_to_snapshot_id_map_entry_t **, + uint32_t *, + uint32_t *); + +extern bool +lit_load_literals_from_snapshot (const uint8_t *, + uint32_t, + lit_mem_to_snapshot_id_map_entry_t **, + uint32_t *); +#endif /* JERRY_ENABLE_SNAPSHOT */ + +#endif /* !RCS_SNAPSHOT_H */ diff --git a/jerry-core/parser/js/bc/bytecode-data.cpp b/jerry-core/parser/js/bc/bytecode-data.cpp index f32fcbdc6c..594b998941 100644 --- a/jerry-core/parser/js/bc/bytecode-data.cpp +++ b/jerry-core/parser/js/bc/bytecode-data.cpp @@ -354,7 +354,7 @@ bc_align_data_in_output_buffer (uint32_t *in_out_size, /**< in: unaligned size, for (uint32_t i = 0; i < padding_bytes_num; i++) { - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, padding)) + if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &padding, sizeof (padding))) { return false; } @@ -426,7 +426,7 @@ bc_save_bytecode_with_idx_map (uint8_t *buffer_p, /**< buffer to dump to */ } uint32_t offset = bc_find_lit_offset (lit_cp, lit_map_p, literals_num); - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, offset)) + if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &offset, sizeof (offset))) { return false; } @@ -466,7 +466,11 @@ bc_save_bytecode_with_idx_map (uint8_t *buffer_p, /**< buffer to dump to */ } /* Dump header at the saved offset */ - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, &bytecode_header_offset, bytecode_header)) + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + &bytecode_header_offset, + &bytecode_header, + sizeof (bytecode_header))) { return false; } @@ -583,7 +587,8 @@ bc_load_bytecode_with_idx_map (const uint8_t *snapshot_data_p, /**< buffer with if (!jrt_read_from_buffer_by_offset (snapshot_data_p, snapshot_size, &buffer_offset, - &bytecode_header)) + &bytecode_header, + sizeof (bytecode_header))) { return NULL; } @@ -609,7 +614,8 @@ bc_load_bytecode_with_idx_map (const uint8_t *snapshot_data_p, /**< buffer with if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p, bytecode_header.idx_to_lit_map_size, &idx_to_lit_map_offset, - &idx_num_total)) + &idx_num_total, + sizeof (idx_num_total))) { return NULL; } @@ -671,7 +677,8 @@ bc_load_bytecode_with_idx_map (const uint8_t *snapshot_data_p, /**< buffer with if (!jrt_read_from_buffer_by_offset (snapshot_data_p, buffer_offset + bytecode_header.var_decls_count * sizeof (uint32_t), &buffer_offset, - &lit_offset_from_snapshot)) + &lit_offset_from_snapshot, + sizeof (lit_offset_from_snapshot))) { mem_heap_free_block (buffer_p); return NULL; @@ -679,7 +686,7 @@ bc_load_bytecode_with_idx_map (const uint8_t *snapshot_data_p, /**< buffer with /** * TODO: implement binary search here */ - lit_cpointer_t lit_cp = lit_cpointer_t::null_cp (); + lit_cpointer_t lit_cp = NOT_A_LITERAL; uint32_t j; for (j = 0; j < literals_num; j++) { diff --git a/jerry-core/parser/js/collections/lit-id-hash-table.cpp b/jerry-core/parser/js/collections/lit-id-hash-table.cpp index 481bec8a6d..d456fd6976 100644 --- a/jerry-core/parser/js/collections/lit-id-hash-table.cpp +++ b/jerry-core/parser/js/collections/lit-id-hash-table.cpp @@ -14,7 +14,6 @@ */ #include "lit-id-hash-table.h" -#include "lit-literal-storage.h" #include "bytecode-data.h" /** \addtogroup jsparser ECMAScript parser @@ -172,7 +171,11 @@ lit_id_hash_table_dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to * uint32_t idx_num_total = (uint32_t) table_p->current_bucket_pos; JERRY_ASSERT (idx_num_total == table_p->current_bucket_pos); - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, idx_num_total)) + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &idx_num_total, + sizeof (idx_num_total))) { return 0; } @@ -207,7 +210,11 @@ lit_id_hash_table_dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to * idx_num_in_block = 0; } - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, idx_num_in_block)) + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &idx_num_in_block, + sizeof (idx_num_in_block))) { return 0; } @@ -220,7 +227,7 @@ lit_id_hash_table_dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to * uint32_t offset = bc_find_lit_offset (lit_cp, lit_map_p, literals_num); - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, offset)) + if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &offset, sizeof (offset))) { return 0; } @@ -230,7 +237,11 @@ lit_id_hash_table_dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to * { idx_num_in_block = 0; - if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, idx_num_in_block)) + if (!jrt_write_to_buffer_by_offset (buffer_p, + buffer_size, + in_out_buffer_offset_p, + &idx_num_in_block, + sizeof (idx_num_in_block))) { return 0; } @@ -278,7 +289,8 @@ lit_id_hash_table_load_from_snapshot (size_t blocks_count, /**< number of byte-c if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p, idx_to_lit_map_size, &idx_to_lit_map_offset, - &idx_num_in_block)) + &idx_num_in_block, + sizeof (idx_num_in_block))) { return false; } @@ -302,7 +314,8 @@ lit_id_hash_table_load_from_snapshot (size_t blocks_count, /**< number of byte-c if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p, idx_to_lit_map_size, &idx_to_lit_map_offset, - &lit_offset_from_snapshot)) + &lit_offset_from_snapshot, + sizeof (lit_offset_from_snapshot))) { return false; } @@ -310,7 +323,7 @@ lit_id_hash_table_load_from_snapshot (size_t blocks_count, /**< number of byte-c /** * TODO: implement binary search here */ - lit_cpointer_t lit_cp = lit_cpointer_t::null_cp (); + lit_cpointer_t lit_cp = rcs_cpointer_null_cp (); uint32_t i; for (i = 0; i < literals_num; i++) { diff --git a/jerry-core/parser/js/collections/lit-id-hash-table.h b/jerry-core/parser/js/collections/lit-id-hash-table.h index 0ac74de43a..75cc674863 100644 --- a/jerry-core/parser/js/collections/lit-id-hash-table.h +++ b/jerry-core/parser/js/collections/lit-id-hash-table.h @@ -20,6 +20,7 @@ #include "ecma-globals.h" #include "opcodes.h" #include "lit-literal.h" +#include "lit-snapshot.h" typedef struct { diff --git a/jerry-core/parser/js/jsp-early-error.cpp b/jerry-core/parser/js/jsp-early-error.cpp index 8ee71f212a..66bcd951e7 100644 --- a/jerry-core/parser/js/jsp-early-error.cpp +++ b/jerry-core/parser/js/jsp-early-error.cpp @@ -38,7 +38,7 @@ jsp_early_error_t jsp_early_error_type; typedef struct { prop_type type; - literal_t lit; + lit_literal_t lit; } prop_literal; enum @@ -97,7 +97,7 @@ jsp_early_error_get_type (void) } /* jsp_early_error_get_type */ static prop_literal -create_prop_literal (literal_t lit, prop_type type) +create_prop_literal (lit_literal_t lit, prop_type type) { prop_literal ret; @@ -189,7 +189,7 @@ jsp_early_error_check_for_duplication_of_prop_names (bool is_strict, locus loc _ } void -jsp_early_error_emit_error_on_eval_and_arguments (literal_t lit, /**< literal to check */ +jsp_early_error_emit_error_on_eval_and_arguments (lit_literal_t lit, /**< literal to check */ locus loc) /**< location of the literal in source code */ { if (lit_literal_equal_type_utf8 (lit, diff --git a/jerry-core/parser/js/jsp-early-error.h b/jerry-core/parser/js/jsp-early-error.h index f889a2a0ed..9ce692c6f8 100644 --- a/jerry-core/parser/js/jsp-early-error.h +++ b/jerry-core/parser/js/jsp-early-error.h @@ -78,7 +78,7 @@ void jsp_early_error_start_checking_of_prop_names (void); void jsp_early_error_add_prop_name (jsp_operand_t, prop_type); void jsp_early_error_check_for_duplication_of_prop_names (bool, locus); -void jsp_early_error_emit_error_on_eval_and_arguments (literal_t, locus); +void jsp_early_error_emit_error_on_eval_and_arguments (lit_literal_t, locus); void jsp_early_error_check_for_eval_and_arguments_in_strict_mode (jsp_operand_t, bool, locus); void jsp_early_error_check_delete (bool, locus); diff --git a/jerry-core/parser/js/lexer.cpp b/jerry-core/parser/js/lexer.cpp index cea3082b6f..6674048b8f 100644 --- a/jerry-core/parser/js/lexer.cpp +++ b/jerry-core/parser/js/lexer.cpp @@ -22,6 +22,7 @@ #include "lit-magic-strings.h" #include "lit-strings.h" #include "jsp-early-error.h" +#include "rcs-records.h" static token saved_token, prev_token, sent_token, empty_token; @@ -119,13 +120,13 @@ dump_current_line (void) } /* dump_current_line */ static token -create_token_from_lit (jsp_token_type_t type, literal_t lit) +create_token_from_lit (jsp_token_type_t type, lit_literal_t lit) { token ret; ret.type = type; ret.loc = current_locus (); - ret.uid = lit_cpointer_t::compress (lit).packed_value; + ret.uid = rcs_cpointer_compress (lit).packed_value; return ret; } @@ -195,7 +196,7 @@ lexer_create_token_for_charset (jsp_token_type_t tt, /**< token type */ JERRY_ASSERT (lit_is_cesu8_string_valid (converted_str_p, new_length)); } - literal_t lit = lit_find_literal_by_utf8_string (converted_str_p, new_length); + lit_literal_t lit = lit_find_literal_by_utf8_string (converted_str_p, new_length); if (lit != NULL) { if (unlikely (should_convert)) @@ -206,9 +207,11 @@ lexer_create_token_for_charset (jsp_token_type_t tt, /**< token type */ return create_token_from_lit (tt, lit); } lit = lit_create_literal_from_utf8_string (converted_str_p, new_length); - JERRY_ASSERT (lit->get_type () == LIT_STR_T - || lit->get_type () == LIT_MAGIC_STR_T - || lit->get_type () == LIT_MAGIC_STR_EX_T); + rcs_record_type_t type = rcs_record_get_type (lit); + + JERRY_ASSERT (RCS_RECORD_TYPE_IS_CHARSET (type) + || RCS_RECORD_TYPE_IS_MAGIC_STR (type) + || RCS_RECORD_TYPE_IS_MAGIC_STR_EX (type)); if (unlikely (should_convert)) { @@ -661,7 +664,7 @@ lexer_parse_reserved_word (const lit_utf8_byte_t *str_p, /**< characters buffer static token convert_seen_num_to_token (ecma_number_t num) { - literal_t lit = lit_find_literal_by_num (num); + lit_literal_t lit = lit_find_literal_by_num (num); if (lit != NULL) { return create_token_from_lit (TOK_NUMBER, lit); diff --git a/jerry-core/parser/js/lexer.h b/jerry-core/parser/js/lexer.h index b435937848..922f8bedfb 100644 --- a/jerry-core/parser/js/lexer.h +++ b/jerry-core/parser/js/lexer.h @@ -19,7 +19,7 @@ #include "lit-literal.h" #include "lit-strings.h" -#define INVALID_LITERAL (rcs_cpointer_t::null_cp ()) +#define INVALID_LITERAL (rcs_cpointer_null_cp ()) /* Keywords. */ typedef enum __attr_packed___ diff --git a/jerry-core/parser/js/opcodes-dumper.h b/jerry-core/parser/js/opcodes-dumper.h index 398b3c2ce7..0c00866949 100644 --- a/jerry-core/parser/js/opcodes-dumper.h +++ b/jerry-core/parser/js/opcodes-dumper.h @@ -21,6 +21,7 @@ #include "lexer.h" #include "lit-literal.h" #include "opcodes.h" +#include "rcs-records.h" #include "scopes-tree.h" /** @@ -163,11 +164,11 @@ class jsp_operand_t JERRY_ASSERT (lit_id.packed_value != NOT_A_LITERAL.packed_value); #ifndef JERRY_NDEBUG - literal_t lit = lit_get_literal_by_cp (lit_id); + lit_literal_t lit = lit_get_literal_by_cp (lit_id); - JERRY_ASSERT (lit->get_type () == LIT_STR_T - || lit->get_type () == LIT_MAGIC_STR_T - || lit->get_type () == LIT_MAGIC_STR_EX_T); + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (lit) + || RCS_RECORD_IS_MAGIC_STR (lit) + || RCS_RECORD_IS_MAGIC_STR_EX (lit)); #endif /* !JERRY_NDEBUG */ jsp_operand_t ret; @@ -189,11 +190,11 @@ class jsp_operand_t JERRY_ASSERT (lit_id.packed_value != NOT_A_LITERAL.packed_value); #ifndef JERRY_NDEBUG - literal_t lit = lit_get_literal_by_cp (lit_id); + lit_literal_t lit = lit_get_literal_by_cp (lit_id); - JERRY_ASSERT (lit->get_type () == LIT_STR_T - || lit->get_type () == LIT_MAGIC_STR_T - || lit->get_type () == LIT_MAGIC_STR_EX_T); + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (lit) + || RCS_RECORD_IS_MAGIC_STR (lit) + || RCS_RECORD_IS_MAGIC_STR_EX (lit)); #endif /* !JERRY_NDEBUG */ jsp_operand_t ret; @@ -215,9 +216,9 @@ class jsp_operand_t JERRY_ASSERT (lit_id.packed_value != NOT_A_LITERAL.packed_value); #ifndef JERRY_NDEBUG - literal_t lit = lit_get_literal_by_cp (lit_id); + lit_literal_t lit = lit_get_literal_by_cp (lit_id); - JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T); + JERRY_ASSERT (RCS_RECORD_IS_NUMBER (lit)); #endif /* !JERRY_NDEBUG */ jsp_operand_t ret; diff --git a/jerry-core/parser/js/parser.cpp b/jerry-core/parser/js/parser.cpp index 9ef7255d12..4982b47849 100644 --- a/jerry-core/parser/js/parser.cpp +++ b/jerry-core/parser/js/parser.cpp @@ -16,6 +16,7 @@ #include "bytecode-data.h" #include "ecma-helpers.h" +#include "jrt-bit-fields.h" #include "jrt-libc-includes.h" #include "jsp-mm.h" #include "opcodes.h" @@ -27,6 +28,7 @@ #include "jsp-early-error.h" #include "jsp-internal.h" #include "vm.h" +#include "rcs-records.h" /** * Flag, indicating whether result of expression @@ -975,9 +977,9 @@ parse_property_name (void) if (is_keyword (tt)) { const char *s = lexer_token_type_to_string (lexer_get_token_type (tok)); - literal_t lit = lit_find_or_create_literal_from_utf8_string ((const lit_utf8_byte_t *) s, + lit_literal_t lit = lit_find_or_create_literal_from_utf8_string ((const lit_utf8_byte_t *) s, (lit_utf8_size_t)strlen (s)); - return jsp_operand_t::make_string_lit_operand (lit_cpointer_t::compress (lit)); + return jsp_operand_t::make_string_lit_operand (rcs_cpointer_compress (lit)); } else { @@ -995,9 +997,9 @@ parse_property_name (void) if (lexer_get_token_type (tok) == TOK_NUMBER) { - literal_t num_lit = lit_get_literal_by_cp (token_data_as_lit_cp ()); - JERRY_ASSERT (num_lit->get_type () == LIT_NUMBER_T); - num = lit_charset_literal_get_number (num_lit); + lit_literal_t num_lit = lit_get_literal_by_cp (token_data_as_lit_cp ()); + JERRY_ASSERT (RCS_RECORD_IS_NUMBER (num_lit)); + num = lit_number_literal_get_number (num_lit); } else { @@ -1008,8 +1010,8 @@ parse_property_name (void) lit_utf8_size_t sz = ecma_number_to_utf8_string (num, buff, sizeof (buff)); JERRY_ASSERT (sz <= ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER); - literal_t str_lit = lit_find_or_create_literal_from_utf8_string (buff, sz); - return jsp_operand_t::make_string_lit_operand (lit_cpointer_t::compress (str_lit)); + lit_literal_t str_lit = lit_find_or_create_literal_from_utf8_string (buff, sz); + return jsp_operand_t::make_string_lit_operand (rcs_cpointer_compress (str_lit)); } case TOK_NULL: case TOK_BOOL: @@ -1017,9 +1019,9 @@ parse_property_name (void) lit_magic_string_id_t id = (token_is (TOK_NULL) ? LIT_MAGIC_STRING_NULL : (tok.uid ? LIT_MAGIC_STRING_TRUE : LIT_MAGIC_STRING_FALSE)); - literal_t lit = lit_find_or_create_literal_from_utf8_string (lit_get_magic_string_utf8 (id), + lit_literal_t lit = lit_find_or_create_literal_from_utf8_string (lit_get_magic_string_utf8 (id), lit_get_magic_string_size (id)); - return jsp_operand_t::make_string_lit_operand (lit_cpointer_t::compress (lit)); + return jsp_operand_t::make_string_lit_operand (rcs_cpointer_compress (lit)); } default: { @@ -1387,7 +1389,7 @@ jsp_start_parse_function_scope (jsp_ctx_t *ctx_p, { current_token_must_be (TOK_NAME); - literal_t current_parameter_name_lit = lit_get_literal_by_cp (token_data_as_lit_cp ()); + lit_literal_t current_parameter_name_lit = lit_get_literal_by_cp (token_data_as_lit_cp ()); locus current_parameter_loc = tok.loc; skip_token (ctx_p); @@ -1409,7 +1411,7 @@ jsp_start_parse_function_scope (jsp_ctx_t *ctx_p, if (lit_utf8_iterator_pos_cmp (tok.loc, current_parameter_loc) != 0) { - literal_t iter_parameter_name_lit = lit_get_literal_by_cp (token_data_as_lit_cp ()); + lit_literal_t iter_parameter_name_lit = lit_get_literal_by_cp (token_data_as_lit_cp ()); if (lit_literal_equal_type (current_parameter_name_lit, iter_parameter_name_lit)) { @@ -2310,24 +2312,24 @@ jsp_get_prop_name_after_dot (void) else if (is_keyword (lexer_get_token_type (tok))) { const char *s = lexer_token_type_to_string (lexer_get_token_type (tok)); - literal_t lit = lit_find_or_create_literal_from_utf8_string ((lit_utf8_byte_t *) s, + lit_literal_t lit = lit_find_or_create_literal_from_utf8_string ((lit_utf8_byte_t *) s, (lit_utf8_size_t) strlen (s)); if (lit == NULL) { EMIT_ERROR (JSP_EARLY_ERROR_SYNTAX, "Expected identifier"); } - return lit_cpointer_t::compress (lit); + return rcs_cpointer_compress (lit); } else if (token_is (TOK_BOOL) || token_is (TOK_NULL)) { lit_magic_string_id_t id = (token_is (TOK_NULL) ? LIT_MAGIC_STRING_NULL : (tok.uid ? LIT_MAGIC_STRING_TRUE : LIT_MAGIC_STRING_FALSE)); - literal_t lit = lit_find_or_create_literal_from_utf8_string (lit_get_magic_string_utf8 (id), + lit_literal_t lit = lit_find_or_create_literal_from_utf8_string (lit_get_magic_string_utf8 (id), lit_get_magic_string_size (id)); - return lit_cpointer_t::compress (lit); + return rcs_cpointer_compress (lit); } else { diff --git a/jerry-core/rcs/rcs-allocator.cpp b/jerry-core/rcs/rcs-allocator.cpp new file mode 100644 index 0000000000..f14e40aaf7 --- /dev/null +++ b/jerry-core/rcs/rcs-allocator.cpp @@ -0,0 +1,395 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rcs-allocator.h" +#include "rcs-records.h" + +/** + * Assert that recordset state is correct. + */ +static void +rcs_assert_state_is_correct (rcs_record_set_t *rec_set_p __attr_unused___) /**< recordset */ +{ +#ifndef JERRY_DISABLE_HEAVY_DEBUG + size_t node_size_sum = 0; + size_t record_size_sum = 0; + + rcs_record_t *last_record_p = NULL; + rcs_record_t *rec_p; + rcs_record_t *next_rec_p; + + for (rec_p = rcs_record_get_first (rec_set_p); + rec_p != NULL; + last_record_p = rec_p, rec_p = next_rec_p) + { + JERRY_ASSERT (rcs_record_get_size (rec_p) > 0); + record_size_sum += rcs_record_get_size (rec_p); + + rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (rec_p); + next_rec_p = rcs_record_get_next (rec_set_p, rec_p); + rcs_chunked_list_t::node_t *next_node_p = NULL; + + if (next_rec_p != NULL) + { + next_node_p = rec_set_p->get_node_from_pointer (next_rec_p); + } + + while (node_p != next_node_p) + { + node_p = rec_set_p->get_next (node_p); + node_size_sum += rcs_get_node_data_space_size (); + } + } + + JERRY_ASSERT (node_size_sum == record_size_sum); + + record_size_sum = 0; + + for (rec_p = last_record_p; + rec_p != NULL; + rec_p = rcs_record_get_prev (rec_set_p, rec_p)) + { + record_size_sum += rcs_record_get_size (rec_p); + } + + JERRY_ASSERT (node_size_sum == record_size_sum); +#endif /* !JERRY_DISABLE_HEAVY_DEBUG */ +} /* rcs_assert_state_is_correct */ + +/** + * Initialize specified record as free record. + */ +static void +rcs_init_free_record (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *rec_p, /**< record to init as free record */ + rcs_record_t *prev_rec_p, /**< previous record (or NULL) */ + size_t size) /**< size, including header */ +{ + rcs_record_set_type (rec_p, RCS_RECORD_TYPE_FREE); + rcs_record_set_prev (rec_set_p, rec_p, prev_rec_p); + rcs_record_set_size (rec_p, size); +} /* rcs_init_free_record */ + +/** + * Check the alignment of the record. + */ +void +rcs_check_record_alignment (rcs_record_t *rec_p) /**< record */ +{ + JERRY_ASSERT (rec_p != NULL); + + uintptr_t ptr = (uintptr_t) rec_p; + + JERRY_ASSERT (JERRY_ALIGNUP (ptr, RCS_DYN_STORAGE_LENGTH_UNIT) == ptr); +} /* rcs_check_record_alignment */ + +/** + * Get size of a node's data space. + * + * @return size + */ +size_t +rcs_get_node_data_space_size (void) +{ + return JERRY_ALIGNDOWN (rcs_chunked_list_t::get_node_data_space_size (), RCS_DYN_STORAGE_LENGTH_UNIT); +} /* rcs_get_node_data_space_size */ + +/** + * Get the node's data space. + * + * @return pointer to beginning of the node's data space + */ +uint8_t * +rcs_get_node_data_space (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_chunked_list_t::node_t *node_p) /**< the node */ +{ + uintptr_t unaligned_data_space_start = (uintptr_t) rec_set_p->get_node_data_space (node_p); + uintptr_t aligned_data_space_start = JERRY_ALIGNUP (unaligned_data_space_start, RCS_DYN_STORAGE_LENGTH_UNIT); + + JERRY_ASSERT (unaligned_data_space_start + rcs_chunked_list_t::get_node_data_space_size () + == aligned_data_space_start + rcs_record_set_t::get_node_data_space_size ()); + + return (uint8_t *) aligned_data_space_start; +} /* rcs_get_node_data_space */ + +/** + * Initialize record in specified place, and, if there is free space + * before next record, initialize free record for the space. + */ +static void +rcs_alloc_record_in_place (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *place_p, /**< where to initialize the record */ + rcs_record_t *next_record_p, /**< next allocated record */ + size_t free_size) /**< size of free part between the allocated record + and the next allocated record */ +{ + const size_t node_data_space_size = rcs_get_node_data_space_size (); + + if (next_record_p != NULL) + { + if (free_size == 0) + { + rcs_record_set_prev (rec_set_p, next_record_p, place_p); + } + else + { + rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (next_record_p); + uint8_t *node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p); + + JERRY_ASSERT ((uint8_t *) next_record_p < node_data_space_p + node_data_space_size); + + rcs_record_t *free_rec_p; + + if ((uint8_t *) next_record_p >= node_data_space_p + free_size) + { + free_rec_p = (rcs_record_t *) ((uint8_t *) next_record_p - free_size); + } + else + { + size_t size_passed_back = (size_t) ((uint8_t *) next_record_p - node_data_space_p); + JERRY_ASSERT (size_passed_back < free_size && size_passed_back + node_data_space_size > free_size); + + node_p = rec_set_p->get_prev (node_p); + node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p); + + free_rec_p = (rcs_record_t *) (node_data_space_p + node_data_space_size - \ + (free_size - size_passed_back)); + } + + rcs_init_free_record (rec_set_p, free_rec_p, place_p, free_size); + } + } + else if (free_size != 0) + { + rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (place_p); + JERRY_ASSERT (node_p != NULL); + + rcs_chunked_list_t::node_t *next_node_p = rec_set_p->get_next (node_p); + + while (next_node_p != NULL) + { + node_p = next_node_p; + next_node_p = rec_set_p->get_next (node_p); + } + + uint8_t *node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p); + const size_t node_data_space_size = rcs_get_node_data_space_size (); + + rcs_record_t *free_rec_p = (rcs_record_t *) (node_data_space_p + node_data_space_size - free_size); + rcs_init_free_record (rec_set_p, free_rec_p, place_p, free_size); + } +} /* rcs_alloc_record_in_place */ + +/** + * Allocate record of specified size. + * + * @return record identifier + */ +static rcs_record_t * +rcs_alloc_space_for_record (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t **out_prev_rec_p, /**< out: pointer to record, previous to the allocated, + * or NULL if the allocated record is the first */ + size_t bytes) /**< size */ +{ + rcs_assert_state_is_correct (rec_set_p); + + JERRY_ASSERT (JERRY_ALIGNUP (bytes, RCS_DYN_STORAGE_LENGTH_UNIT) == bytes); + JERRY_ASSERT (out_prev_rec_p != NULL); + + rcs_record_t *rec_p = NULL; + *out_prev_rec_p = NULL; + + const size_t node_data_space_size = rcs_get_node_data_space_size (); + + for (rec_p = rcs_record_get_first (rec_set_p); + rec_p != NULL; + *out_prev_rec_p = rec_p, rec_p = rcs_record_get_next (rec_set_p, rec_p)) + { + if (RCS_RECORD_IS_FREE (rec_p)) + { + rcs_record_t *next_rec_p = rcs_record_get_next (rec_set_p, rec_p); + size_t record_size = rcs_record_get_size (rec_p); + + if (record_size >= bytes) + { + /* Record size is sufficient. */ + rcs_alloc_record_in_place (rec_set_p, rec_p, next_rec_p, record_size - bytes); + return rec_p; + } + + rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (rec_p); + uint8_t *node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p); + uint8_t *node_data_space_end_p = node_data_space_p + node_data_space_size; + uint8_t *rec_space_p = (uint8_t *) rec_p; + + if (rec_space_p + record_size >= node_data_space_end_p) + { + /* Record lies up to end of node's data space size, + * thus it can be extended up to necessary size. */ + while (record_size < bytes) + { + node_p = rec_set_p->insert_new (node_p); + record_size += node_data_space_size; + } + + rcs_alloc_record_in_place (rec_set_p, rec_p, next_rec_p, record_size - bytes); + return rec_p; + } + + if (next_rec_p == NULL) + { + /* There are no more records in the storage, + * so we should append a new record. */ + break; + } + + JERRY_ASSERT (!RCS_RECORD_IS_FREE (rec_p)); + } + } + + /* Free record of sufficient size was not found. */ + rcs_chunked_list_t::node_t *node_p = rec_set_p->append_new (); + rcs_record_t *new_rec_p = (rcs_record_t *) rcs_get_node_data_space (rec_set_p, node_p); + + size_t allocated_size = node_data_space_size; + + while (allocated_size < bytes) + { + allocated_size += node_data_space_size; + rec_set_p->append_new (); + } + + rcs_alloc_record_in_place (rec_set_p, new_rec_p, NULL, allocated_size - bytes); + + return new_rec_p; +} /* rcs_alloc_space_for_record */ + +/** + * Allocate and initialize a new record. + * + * @return pointer to the new record + */ +rcs_record_t * +rcs_alloc_record (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_type_t type, /**< type for the new record */ + size_t size) /**< allocation size */ +{ + JERRY_ASSERT (type >= RCS_RECORD_TYPE_FIRST && type <= RCS_RECORD_TYPE_LAST); + + rcs_record_t *prev_rec_p; + rcs_record_t *rec_p = (rcs_record_t *) rcs_alloc_space_for_record (rec_set_p, &prev_rec_p, size); + + rcs_record_set_type (rec_p, type); + rcs_record_set_size (rec_p, size); + rcs_record_set_prev (rec_set_p, rec_p, prev_rec_p); + + rcs_assert_state_is_correct (rec_set_p); + + return rec_p; +} /* alloc_record */ + +/** + * Free the specified record. + */ +void +rcs_free_record (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *record_p) /**< record to free */ +{ + JERRY_ASSERT (record_p != NULL); + + rcs_assert_state_is_correct (rec_set_p); + + rcs_record_t *prev_rec_p = rcs_record_get_prev (rec_set_p, record_p); + + rcs_init_free_record (rec_set_p, record_p, prev_rec_p, rcs_record_get_size (record_p)); + + /* Merge adjacent free records, if there are any, + * and free nodes of chunked list that became unused. */ + rcs_record_t *rec_from_p = record_p; + rcs_record_t *rec_to_p = rcs_record_get_next (rec_set_p, record_p); + + if (prev_rec_p != NULL && RCS_RECORD_IS_FREE (prev_rec_p)) + { + rec_from_p = prev_rec_p; + prev_rec_p = rcs_record_get_prev (rec_set_p, rec_from_p); + } + + if (rec_to_p != NULL && RCS_RECORD_IS_FREE (rec_to_p)) + { + rec_to_p = rcs_record_get_next (rec_set_p, rec_to_p); + } + + JERRY_ASSERT (rec_from_p != NULL && RCS_RECORD_IS_FREE (rec_from_p)); + JERRY_ASSERT (rec_to_p == NULL || !RCS_RECORD_IS_FREE (rec_to_p)); + + rcs_chunked_list_t::node_t *node_from_p = rec_set_p->get_node_from_pointer (rec_from_p); + rcs_chunked_list_t::node_t *node_to_p = NULL; + + if (rec_to_p != NULL) + { + node_to_p = rec_set_p->get_node_from_pointer (rec_to_p); + } + + const size_t node_data_space_size = rcs_get_node_data_space_size (); + + uint8_t *rec_from_beg_p = (uint8_t *) rec_from_p; + uint8_t *rec_to_beg_p = (uint8_t *) rec_to_p; + size_t free_size; + + if (node_from_p == node_to_p) + { + JERRY_ASSERT (rec_from_beg_p + rcs_record_get_size (rec_from_p) <= rec_to_beg_p); + free_size = (size_t) (rec_to_beg_p - rec_from_beg_p); + } + else + { + rcs_chunked_list_t::node_t *iter_node_p; + rcs_chunked_list_t::node_t *iter_next_node_p; + + for (iter_node_p = rec_set_p->get_next (node_from_p); + iter_node_p != node_to_p; + iter_node_p = iter_next_node_p) + { + iter_next_node_p = rec_set_p->get_next (iter_node_p); + rec_set_p->remove (iter_node_p); + } + + JERRY_ASSERT (rec_set_p->get_next (node_from_p) == node_to_p); + + size_t node_from_space = (size_t) (rcs_get_node_data_space (rec_set_p, node_from_p) \ + + node_data_space_size - rec_from_beg_p); + size_t node_to_space = (size_t) (node_to_p != NULL ? \ + (rec_to_beg_p - rcs_get_node_data_space (rec_set_p, node_to_p)) : 0); + + free_size = node_from_space + node_to_space; + } + + rcs_init_free_record (rec_set_p, rec_from_p, prev_rec_p, free_size); + + if (rec_to_p != NULL) + { + rcs_record_set_prev (rec_set_p, rec_to_p, rec_from_p); + } + else if (prev_rec_p == NULL) + { + rec_set_p->remove (node_from_p); + + JERRY_ASSERT (node_to_p == NULL); + JERRY_ASSERT (rec_set_p->get_first () == NULL); + } + + rcs_assert_state_is_correct (rec_set_p); +} /* rcs_free_record */ diff --git a/jerry-core/rcs/rcs-allocator.h b/jerry-core/rcs/rcs-allocator.h new file mode 100644 index 0000000000..57db2fa0cc --- /dev/null +++ b/jerry-core/rcs/rcs-allocator.h @@ -0,0 +1,28 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RCS_ALLOCATOR_H +#define RCS_ALLOCATOR_H + +#include "rcs-globals.h" + +extern void rcs_check_record_alignment (rcs_record_t *); +extern void rcs_free_record (rcs_record_set_t *, rcs_record_t *); +extern size_t rcs_get_node_data_space_size (void); +extern uint8_t *rcs_get_node_data_space (rcs_record_set_t *, rcs_chunked_list_t::node_t *); +extern rcs_record_t *rcs_alloc_record (rcs_record_set_t *, rcs_record_type_t, size_t); + +#endif /* !RCS_ALLOCATOR_H */ diff --git a/jerry-core/rcs/rcs-cpointer.cpp b/jerry-core/rcs/rcs-cpointer.cpp new file mode 100644 index 0000000000..3e98325fb1 --- /dev/null +++ b/jerry-core/rcs/rcs-cpointer.cpp @@ -0,0 +1,104 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rcs-cpointer.h" +#include "jrt-bit-fields.h" + +/** + * Compress pointer to extended compressed pointer. + * + * @return dynamic storage-specific extended compressed pointer + */ +rcs_cpointer_t +rcs_cpointer_compress (rcs_record_t *pointer) /**< pointer to compress */ +{ + rcs_cpointer_t cpointer; + cpointer.packed_value = 0; + + uintptr_t base_pointer = JERRY_ALIGNDOWN ((uintptr_t) pointer, MEM_ALIGNMENT); + + if ((void *) base_pointer == NULL) + { + cpointer.value.base_cp = MEM_CP_NULL; + } + else + { + cpointer.value.base_cp = mem_compress_pointer ((void *) base_pointer) & MEM_CP_MASK; + } + +#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG + /* + * If alignment of a unit in recordset storage is less than required by MEM_ALIGNMENT_LOG, + * then mem_cpointer_t can't store pointer to the unit, and so, rcs_cpointer_t stores + * mem_cpointer_t to block, aligned to MEM_ALIGNMENT, and also extension with difference + * between positions of the MEM_ALIGNMENT-aligned block and the unit. + */ + uintptr_t diff = (uintptr_t) pointer - base_pointer; + + JERRY_ASSERT (diff < MEM_ALIGNMENT); + JERRY_ASSERT (jrt_extract_bit_field (diff, 0, RCS_DYN_STORAGE_LENGTH_UNIT_LOG) == 0); + + uintptr_t ext_part = (uintptr_t) jrt_extract_bit_field (diff, + RCS_DYN_STORAGE_LENGTH_UNIT_LOG, + MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG); + + cpointer.value.ext = ext_part & ((1ull << (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG)) - 1); +#endif /* MEM_ALIGNMENT > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */ + JERRY_ASSERT (rcs_cpointer_decompress (cpointer) == pointer); + + return cpointer; +} /* rcs_cpointer_compress */ + +/** + * Decompress extended compressed pointer. + * + * @return decompressed pointer + */ +rcs_record_t * +rcs_cpointer_decompress (rcs_cpointer_t compressed_pointer) /**< recordset-specific compressed pointer */ +{ + uint8_t *base_pointer = NULL; + + if (compressed_pointer.value.base_cp != MEM_CP_NULL) + { + base_pointer = (uint8_t *) mem_decompress_pointer (compressed_pointer.value.base_cp); + } + + uintptr_t diff = 0; +#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG + /* + * See also: + * rcs_cpointer_compress + */ + + diff = (uintptr_t) compressed_pointer.value.ext << RCS_DYN_STORAGE_LENGTH_UNIT_LOG; +#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */ + rcs_record_t *rec_p = (rcs_record_t *) (base_pointer + diff); + + return rec_p; +} /* rcs_cpointer_decompress */ + +/** + * Create NULL compressed pointer. + * + * @return NULL compressed pointer + */ +rcs_cpointer_t rcs_cpointer_null_cp (void) +{ + rcs_cpointer_t cp; + cp.packed_value = MEM_CP_NULL; + return cp; +} /* rcs_cpointer_null_cp */ diff --git a/jerry-core/rcs/rcs-cpointer.h b/jerry-core/rcs/rcs-cpointer.h new file mode 100644 index 0000000000..cf9339a24e --- /dev/null +++ b/jerry-core/rcs/rcs-cpointer.h @@ -0,0 +1,53 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RCS_CPOINTER_H +#define RCS_CPOINTER_H + +#include "rcs-globals.h" + +#define RCS_CPOINTER_WIDTH (MEM_CP_WIDTH + MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG) + +/** + * Dynamic storage-specific extended compressed pointer + * + * Note: + * the pointer can represent addresses aligned by RCS_DYN_STORAGE_LENGTH_UNIT, + * while mem_cpointer_t can only represent addresses aligned by MEM_ALIGNMENT. + */ +typedef struct +{ + union + { + struct + { + mem_cpointer_t base_cp : MEM_CP_WIDTH; /**< pointer to base of addressed area */ +#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG + uint16_t ext : (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG); /**< extension of the basic + * compressed pointer + * used for more detailed + * addressing */ +#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */ + } value; + uint16_t packed_value; + }; +} rcs_cpointer_t; + +extern rcs_cpointer_t rcs_cpointer_compress (rcs_record_t *); +extern rcs_record_t *rcs_cpointer_decompress (rcs_cpointer_t); +extern rcs_cpointer_t rcs_cpointer_null_cp (); + +#endif /* !RCS_CPOINTER_H */ diff --git a/jerry-core/rcs/rcs-globals.h b/jerry-core/rcs/rcs-globals.h new file mode 100644 index 0000000000..0196fcade3 --- /dev/null +++ b/jerry-core/rcs/rcs-globals.h @@ -0,0 +1,54 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RCS_GLOBALS_H +#define RCS_GLOBALS_H + +#include "rcs-chunked-list.h" + +/** + * Represents the type of the record. + */ +typedef enum +{ + RCS_RECORD_TYPE_FREE = 0, /**< Free record that marks an empty space. It doesn't hold any values. */ + RCS_RECORD_TYPE_CHARSET = 1, /**< Charset record that holds characters. */ + RCS_RECORD_TYPE_MAGIC_STR = 2, /**< Magic string record that holds a magic string id. */ + RCS_RECORD_TYPE_MAGIC_STR_EX = 3, /**< External magic string record that holds an extrernal magic string id. */ + RCS_RECORD_TYPE_NUMBER = 4 /**< Number record that holds a numeric value. */ +} rcs_record_type_t; + +/** + * Record type + */ +typedef uint8_t rcs_record_t; + +/** + * Recordset type + */ +typedef rcs_chunked_list_t rcs_record_set_t; + +/** + * Logarithm of a dynamic storage unit alignment + */ +#define RCS_DYN_STORAGE_LENGTH_UNIT_LOG (2u) + +/** + * Unit of length + */ +#define RCS_DYN_STORAGE_LENGTH_UNIT ((size_t) (1ull << RCS_DYN_STORAGE_LENGTH_UNIT_LOG)) + +#endif /* !RCS_GLOBALS_H */ diff --git a/jerry-core/rcs/rcs-iterator.cpp b/jerry-core/rcs/rcs-iterator.cpp new file mode 100644 index 0000000000..abc1182149 --- /dev/null +++ b/jerry-core/rcs/rcs-iterator.cpp @@ -0,0 +1,214 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rcs-iterator.h" +#include "rcs-allocator.h" +#include "rcs-records.h" + +/** + * Represents the memory access on the literal storage. + */ +typedef enum +{ + RCS_ITERATOR_ACCESS_WRITE = 0, /**< Write 'size' bytes from 'data' buffer to the record. */ + RCS_ITERATOR_ACCESS_READ = 1, /**< Read 'size' bytes from the record and write to the 'data' buffer. */ + RCS_ITERATOR_ACCESS_SKIP = 2 /**< Increment current position so that 'size' bytes would be skipped. */ +} rcs_access_t; + +/** + * Create an iterator context. + * + * @return an initialized iterator context + */ +rcs_iterator_t +rcs_iterator_create (rcs_record_set_t *recordset_p, /**< recordset */ + rcs_record_t *record_p) /**< start record */ +{ + rcs_iterator_t ctx; + { + ctx.recordset_p = recordset_p; + ctx.record_start_p = record_p; + + rcs_iterator_reset (&ctx); + } + + return ctx; +} /* rcs_iterator_create */ + +/** + * Perform general access to the record + * + * Warning: This function is implemented in assumption that `size` is not more than `2 * node_data_space_size`. + */ +static void +rcs_iterator_access (rcs_iterator_t *ctx_p, /**< iterator context */ + void *data, /**< iterator context */ + size_t size, /**< iterator context */ + rcs_access_t access_type) /**< access type */ +{ + const size_t node_data_space_size = rcs_get_node_data_space_size (); + JERRY_ASSERT (2 * node_data_space_size >= size); + const size_t record_size = rcs_record_get_size (ctx_p->record_start_p); + + JERRY_ASSERT (!rcs_iterator_finished (ctx_p)); + + rcs_chunked_list_t::node_t *current_node_p = ctx_p->recordset_p->get_node_from_pointer (ctx_p->current_pos_p); + uint8_t *current_node_data_space_p = rcs_get_node_data_space (ctx_p->recordset_p, current_node_p); + size_t left_in_node = node_data_space_size - (size_t) (ctx_p->current_pos_p - current_node_data_space_p); + + JERRY_ASSERT (ctx_p->current_offset + size <= record_size); + + /* + * Read the data and increase the current position pointer. + */ + if (left_in_node >= size) + { + /* all data is placed inside single node */ + if (access_type == RCS_ITERATOR_ACCESS_READ) + { + memcpy (data, ctx_p->current_pos_p, size); + } + else if (access_type == RCS_ITERATOR_ACCESS_WRITE) + { + memcpy (ctx_p->current_pos_p, data, size); + } + else + { + JERRY_ASSERT (access_type == RCS_ITERATOR_ACCESS_SKIP); + + if (left_in_node > size) + { + ctx_p->current_pos_p += size; + } + else if (ctx_p->current_offset + size < record_size) + { + current_node_p = ctx_p->recordset_p->get_next (current_node_p); + JERRY_ASSERT (current_node_p); + ctx_p->current_pos_p = rcs_get_node_data_space (ctx_p->recordset_p, current_node_p); + } + else + { + JERRY_ASSERT (ctx_p->current_offset + size == record_size); + } + } + } + else + { + /* Data is distributed between two nodes. */ + const size_t first_chunk_size = node_data_space_size - (size_t) (ctx_p->current_pos_p - current_node_data_space_p); + + if (access_type == RCS_ITERATOR_ACCESS_READ) + { + memcpy (data, ctx_p->current_pos_p, first_chunk_size); + } + else if (access_type == RCS_ITERATOR_ACCESS_WRITE) + { + memcpy (ctx_p->current_pos_p, data, first_chunk_size); + } + + rcs_chunked_list_t::node_t *next_node_p = ctx_p->recordset_p->get_next (current_node_p); + JERRY_ASSERT (next_node_p != NULL); + uint8_t *next_node_data_space_p = rcs_get_node_data_space (ctx_p->recordset_p, next_node_p); + + if (access_type == RCS_ITERATOR_ACCESS_READ) + { + memcpy ((uint8_t *)data + first_chunk_size, next_node_data_space_p, size - first_chunk_size); + } + else if (access_type == RCS_ITERATOR_ACCESS_WRITE) + { + memcpy (next_node_data_space_p, (uint8_t *)data + first_chunk_size, size - first_chunk_size); + } + else + { + JERRY_ASSERT (access_type == RCS_ITERATOR_ACCESS_SKIP); + ctx_p->current_pos_p = next_node_data_space_p + size - first_chunk_size; + } + } + + /* Check if we reached the end. */ + if (access_type == RCS_ITERATOR_ACCESS_SKIP) + { + ctx_p->current_offset += size; + JERRY_ASSERT (ctx_p->current_offset <= record_size); + + if (ctx_p->current_offset == record_size) + { + ctx_p->current_pos_p = NULL; + ctx_p->current_offset = 0; + } + } +} /* rcs_iterator_access */ + +/** + * Read a value from the record. + * After reading iterator doesn't change its position. + * + * @return read value + */ +void +rcs_iterator_read (rcs_iterator_t *ctx_p, /**< iterator context */ + void *out_data, /**< value to read */ + size_t size) /**< size to read */ +{ + rcs_iterator_access (ctx_p, out_data, size, RCS_ITERATOR_ACCESS_READ); +} /* rcs_iterator_read */ + +/** + * Write a value to the record. + * After writing, iterator doesn't change its position. + */ +void +rcs_iterator_write (rcs_iterator_t *ctx_p, /**< iterator context */ + void *value, /**< value to write */ + size_t size) /**< size to write */ +{ + rcs_iterator_access (ctx_p, value, size, RCS_ITERATOR_ACCESS_WRITE); +} /* rcs_iterator_write */ + +/** + * Increment current position to skip 'size' bytes. + */ +void +rcs_iterator_skip (rcs_iterator_t *ctx_p, /**< iterator context */ + size_t size) /**< size to skip */ +{ + if (size) + { + rcs_iterator_access (ctx_p, NULL, size, RCS_ITERATOR_ACCESS_SKIP); + } +} /* rcs_iterator_skip */ + +/** + * Reset the iterator, so that it points to the beginning of the record. + */ +void +rcs_iterator_reset (rcs_iterator_t *ctx_p) /**< iterator context */ +{ + ctx_p->current_pos_p = ctx_p->record_start_p; + ctx_p->current_offset = 0; +} /* rcs_iterator_reset */ + +/** + * Check if the end of the record was reached. + * + * @return true if the whole record was iterated + * false otherwise + */ +bool +rcs_iterator_finished (rcs_iterator_t *ctx_p) /**< iterator context */ +{ + return ctx_p->current_pos_p == NULL; +} /* rcs_iterator_finished */ diff --git a/jerry-core/rcs/rcs-iterator.h b/jerry-core/rcs/rcs-iterator.h new file mode 100644 index 0000000000..46a8fc73c8 --- /dev/null +++ b/jerry-core/rcs/rcs-iterator.h @@ -0,0 +1,42 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RCS_ITERATOR_H +#define RCS_ITERATOR_H + +#include "ecma-globals.h" + +/** + * Represents a context for the iterator. + */ +typedef struct +{ + rcs_record_set_t *recordset_p; /**< recordset, containing the records */ + rcs_record_t *record_start_p; /**< start of current record */ + uint8_t *current_pos_p; /**< pointer to current offset in current record */ + size_t current_offset; /**< current offset */ +} rcs_iterator_t; + +extern rcs_iterator_t rcs_iterator_create (rcs_record_set_t *, rcs_record_t *); + +extern void rcs_iterator_write (rcs_iterator_t *, void *, size_t); +extern void rcs_iterator_read (rcs_iterator_t *, void *, size_t); +extern void rcs_iterator_skip (rcs_iterator_t *, size_t); + +extern void rcs_iterator_reset (rcs_iterator_t *); +extern bool rcs_iterator_finished (rcs_iterator_t *); + +#endif /* !RCS_ITERATOR_H */ diff --git a/jerry-core/rcs/rcs-records.cpp b/jerry-core/rcs/rcs-records.cpp new file mode 100644 index 0000000000..8a12c25706 --- /dev/null +++ b/jerry-core/rcs/rcs-records.cpp @@ -0,0 +1,636 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rcs-records.h" + +#include "rcs-allocator.h" +#include "rcs-cpointer.h" +#include "rcs-iterator.h" +#include "jrt-bit-fields.h" + +/** + * Set value of the record's field with specified offset and width. + */ +static void +rcs_record_set_field (rcs_record_t *rec_p, /**< record */ + uint32_t field_pos, /**< offset, in bits */ + uint32_t field_width, /**< width, in bits */ + size_t value) /**< 32-bit unsigned integer value */ +{ + rcs_check_record_alignment (rec_p); + + JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT); + JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE); + + uint32_t prev_value = *(uint32_t *) rec_p; + *(uint32_t *) rec_p = (uint32_t) jrt_set_bit_field_value (prev_value, value, field_pos, field_width); +} /* rcs_record_set_field */ + +/** + * Set the record's type identifier. + */ +void +rcs_record_set_type (rcs_record_t *rec_p, /**< record */ + rcs_record_type_t type) /**< record type */ +{ + JERRY_ASSERT (RCS_RECORD_TYPE_IS_VALID (type)); + + rcs_record_set_field (rec_p, RCS_HEADER_TYPE_POS, RCS_HEADER_TYPE_WIDTH, type); +} /* rcs_record_set_type */ + +/** + * Set previous record for the records. + */ +void +rcs_record_set_prev (rcs_record_set_t *rec_sec_p, /**< recordset */ + rcs_record_t *rec_p, /**< record */ + rcs_record_t *prev_p) /**< prev record */ +{ + uint8_t begin_pos; + + switch (rcs_record_get_type (rec_p)) + { + case RCS_RECORD_TYPE_CHARSET: + { + rcs_cpointer_t prev_cpointer = rcs_cpointer_compress (prev_p); + rcs_iterator_t it_ctx = rcs_iterator_create (rec_sec_p, rec_p); + + rcs_iterator_skip (&it_ctx, RCS_DYN_STORAGE_LENGTH_UNIT); + rcs_iterator_write (&it_ctx, &prev_cpointer.packed_value, sizeof (uint16_t)); + + return; + } + case RCS_RECORD_TYPE_FREE: + { + begin_pos = RCS_FREE_HEADER_PREV_POS; + break; + } + case RCS_RECORD_TYPE_MAGIC_STR: + case RCS_RECORD_TYPE_MAGIC_STR_EX: + { + begin_pos = RCS_MAGIC_STR_HEADER_PREV_POS; + break; + } + case RCS_RECORD_TYPE_NUMBER: + { + begin_pos = RCS_NUMBER_HEADER_PREV_POS; + break; + } + default: + { + JERRY_UNREACHABLE (); + } + } + + rcs_cpointer_t cpointer = rcs_cpointer_compress (prev_p); + rcs_record_set_field (rec_p, begin_pos, RCS_CPOINTER_WIDTH, cpointer.packed_value); +} /* rcs_record_set_prev */ + +/** + * Set size of the records. + */ +void +rcs_record_set_size (rcs_record_t *rec_p, /**< recordset */ + size_t size) /**< record size */ +{ + rcs_record_type_t type = rcs_record_get_type (rec_p); + + if (RCS_RECORD_TYPE_IS_CHARSET (type)) + { + JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size); + + rcs_record_set_field (rec_p, + RCS_CHARSET_HEADER_LENGTH_POS, + RCS_CHARSET_HEADER_LENGTH_WIDTH, + size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG); + return; + } + + if (RCS_RECORD_TYPE_IS_FREE (type)) + { + JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size); + + rcs_record_set_field (rec_p, + RCS_FREE_HEADER_LENGTH_POS, + RCS_FREE_HEADER_LENGTH_WIDTH, + size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG); + return; + } + + JERRY_ASSERT (rcs_record_get_size (rec_p) == size); +} /* rcs_record_set_size */ + +/** + * Set the count of the alignment bytes at the end of record. + */ +void +rcs_record_set_alignment_bytes_count (rcs_record_t *rec_p, /**< record */ + size_t count) /**< align bytes */ +{ + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p)); + + rcs_record_set_field (rec_p, RCS_CHARSET_HEADER_ALIGN_POS, RCS_CHARSET_HEADER_ALIGN_WIDTH, count); +} /* rcs_record_set_align */ + +/** + * Set the hash value of the record. + */ +void +rcs_record_set_hash (rcs_record_t *rec_p, /**< record */ + lit_string_hash_t hash) /**< hash value */ +{ + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p)); + + rcs_record_set_field (rec_p, RCS_CHARSET_HEADER_HASH_POS, RCS_CHARSET_HEADER_HASH_WIDTH, hash); +} /* rcs_record_set_hash */ + +/** + * Set the charset of the record. + */ +void +rcs_record_set_charset (rcs_record_set_t *rec_set_p, /**< recordset containing the records */ + rcs_record_t *rec_p, /**< record */ + const lit_utf8_byte_t *str_p, /**< buffer containing characters to set */ + lit_utf8_size_t size) /**< size of the buffer in bytes */ +{ + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p)); + JERRY_ASSERT (RCS_CHARSET_HEADER_SIZE + size + == rcs_record_get_size (rec_p) - rcs_record_get_alignment_bytes_count (rec_p)); + + rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p); + rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE); + + lit_utf8_size_t str_len = rcs_record_get_length (rec_p); + lit_utf8_size_t i; + + for (i = 0; i < str_len; ++i) + { + rcs_iterator_write (&it_ctx, (void *)(str_p + i), sizeof (lit_utf8_byte_t)); + rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t)); + } +} /* rcs_record_set_charset */ + +/** + * Set the magic string id of the record. + */ +void +rcs_record_set_magic_str_id (rcs_record_t *rec_p, /**< record */ + lit_magic_string_id_t id) /**< magic string id */ +{ + JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR (rec_p)); + + rcs_record_set_field (rec_p, RCS_MAGIC_STR_HEADER_ID_POS, RCS_MAGIC_STR_HEADER_ID_WIDTH, id); +} /* rcs_record_set_magic_str_id */ + +/** + * Set the external magic string id of the record. + */ +void +rcs_record_set_magic_str_ex_id (rcs_record_t *rec_p, /**< record */ + lit_magic_string_ex_id_t id) /**< external magic string id */ +{ + JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR_EX (rec_p)); + + rcs_record_set_field (rec_p, RCS_MAGIC_STR_HEADER_ID_POS, RCS_MAGIC_STR_HEADER_ID_WIDTH, id); +} /* rcs_record_set_magic_str_ex_id */ + +/** + * Get value of the record's field with specified offset and width. + * + * @return field's 32-bit unsigned integer value + */ +static uint32_t +rcs_record_get_field (rcs_record_t *rec_p, /**< record */ + uint32_t field_pos, /**< offset, in bits */ + uint32_t field_width) /**< width, in bits */ +{ + rcs_check_record_alignment (rec_p); + + JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT); + JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE); + + uint32_t value = *(uint32_t *) rec_p; + return (uint32_t) jrt_extract_bit_field (value, field_pos, field_width); +} /* rcs_record_get_field */ + +/** + * Get value of the record's pointer field with specified offset and width. + * + * @return pointer to record + */ +static rcs_record_t * +rcs_record_get_pointer (rcs_record_t *rec_p, /**< record */ + uint32_t field_pos, /**< offset, in bits */ + uint32_t field_width) /**< width, in bits */ +{ + rcs_cpointer_t cpointer; + + uint16_t value = (uint16_t) rcs_record_get_field (rec_p, field_pos, field_width); + + JERRY_ASSERT (sizeof (cpointer) == sizeof (cpointer.value)); + JERRY_ASSERT (sizeof (value) == sizeof (cpointer.value)); + + cpointer.packed_value = value; + + return rcs_cpointer_decompress (cpointer); +} /* rcs_record_get_pointer */ + +/** + * Get the record's type identifier. + * + * @return record type identifier + */ +rcs_record_type_t +rcs_record_get_type (rcs_record_t *rec_p) /**< record */ +{ + JERRY_STATIC_ASSERT (sizeof (rcs_record_type_t) * JERRY_BITSINBYTE >= RCS_HEADER_TYPE_WIDTH); + + return (rcs_record_type_t) rcs_record_get_field (rec_p, RCS_HEADER_TYPE_POS, RCS_HEADER_TYPE_WIDTH); +} /* rcs_record_get_type */ + +/** + * Get previous record for the records. + * + * @return previous record + */ +rcs_record_t * +rcs_record_get_prev (rcs_record_set_t *rec_sec_p, /**< recordset */ + rcs_record_t *rec_p) /**< record */ +{ + uint8_t begin_pos; + + switch (rcs_record_get_type (rec_p)) + { + case RCS_RECORD_TYPE_CHARSET: + { + rcs_cpointer_t cpointer; + rcs_iterator_t it_ctx = rcs_iterator_create (rec_sec_p, rec_p); + + rcs_iterator_skip (&it_ctx, RCS_DYN_STORAGE_LENGTH_UNIT); + rcs_iterator_read (&it_ctx, &cpointer.packed_value, sizeof (uint16_t)); + + return rcs_cpointer_decompress (cpointer); + } + case RCS_RECORD_TYPE_FREE: + { + begin_pos = RCS_FREE_HEADER_PREV_POS; + break; + } + case RCS_RECORD_TYPE_MAGIC_STR: + case RCS_RECORD_TYPE_MAGIC_STR_EX: + { + begin_pos = RCS_MAGIC_STR_HEADER_PREV_POS; + break; + } + case RCS_RECORD_TYPE_NUMBER: + { + begin_pos = RCS_NUMBER_HEADER_PREV_POS; + break; + } + default: + { + JERRY_UNREACHABLE (); + } + } + + return rcs_record_get_pointer (rec_p, begin_pos, RCS_CPOINTER_WIDTH); +} /* rcs_record_get_prev */ + +/** + * Get the count of the alignment bytes at the end of record. + * These bytes are needed to align the record to RCS_DYN_STORAGE_ALIGNMENT. + * + * @return alignment bytes count + */ +size_t +rcs_record_get_alignment_bytes_count (rcs_record_t *rec_p) /**< record */ +{ + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p)); + + return rcs_record_get_field (rec_p, RCS_CHARSET_HEADER_ALIGN_POS, RCS_CHARSET_HEADER_ALIGN_WIDTH); +} /* rcs_record_get_alignment_bytes_count */ + +/** + * Get hash value of the record's charset. + * + * @return hash value of the string + */ +lit_string_hash_t +rcs_record_get_hash (rcs_record_t *rec_p) /**< record */ +{ + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p)); + + return (lit_string_hash_t) rcs_record_get_field (rec_p, RCS_CHARSET_HEADER_HASH_POS, RCS_CHARSET_HEADER_HASH_WIDTH); +} /* rcs_record_get_hash */ + +/** + * Get header size of the records. + * + * @return size of the header in bytes + */ +size_t +rcs_header_get_size (rcs_record_t *rec_p) /**< record */ +{ + if (RCS_RECORD_IS_CHARSET (rec_p)) + { + return RCS_CHARSET_HEADER_SIZE; + } + + return RCS_DYN_STORAGE_LENGTH_UNIT; +} /* rcs_header_get_size */ + +/** + * Get size of the records. + * + * @return size of the record in bytes + */ +size_t +rcs_record_get_size (rcs_record_t *rec_p) /**< record */ +{ + switch (rcs_record_get_type (rec_p)) + { + case RCS_RECORD_TYPE_CHARSET: + { + size_t size = rcs_record_get_field (rec_p, RCS_CHARSET_HEADER_LENGTH_POS, RCS_CHARSET_HEADER_LENGTH_WIDTH); + return (size * RCS_DYN_STORAGE_LENGTH_UNIT); + } + case RCS_RECORD_TYPE_FREE: + { + size_t size = rcs_record_get_field (rec_p, RCS_FREE_HEADER_LENGTH_POS, RCS_FREE_HEADER_LENGTH_WIDTH); + return (size * RCS_DYN_STORAGE_LENGTH_UNIT); + } + case RCS_RECORD_TYPE_NUMBER: + { + return (RCS_DYN_STORAGE_LENGTH_UNIT + sizeof (ecma_number_t)); + } + case RCS_RECORD_TYPE_MAGIC_STR: + case RCS_RECORD_TYPE_MAGIC_STR_EX: + { + return RCS_DYN_STORAGE_LENGTH_UNIT; + } + default: + { + JERRY_UNREACHABLE (); + return 0; + } + } +} /* rcs_record_get_size */ + +/** + * Get the length of the string, which is contained inside the record. + * + * @return length of the string (bytes count) + */ +lit_utf8_size_t +rcs_record_get_length (rcs_record_t *rec_p) /**< record */ +{ + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p)); + + size_t record_size = rcs_record_get_size (rec_p); + size_t align_count = rcs_record_get_alignment_bytes_count (rec_p); + + return (lit_utf8_size_t) (record_size - RCS_CHARSET_HEADER_SIZE - align_count); +} /* rcs_record_get_length */ + +/** + * Get magic string id which is held by the record. + * + * @return magic string id + */ +lit_magic_string_id_t +rcs_record_get_magic_str_id (rcs_record_t *rec_p) /**< record */ +{ + JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR (rec_p)); + + return (lit_magic_string_id_t) rcs_record_get_field (rec_p, + RCS_MAGIC_STR_HEADER_ID_POS, + RCS_MAGIC_STR_HEADER_ID_WIDTH); +} /* rcs_record_get_magic_str_id */ + +/** + * Get external magic string id which is held by the record. + * + * @return external magic string id + */ +lit_magic_string_ex_id_t +rcs_record_get_magic_str_ex_id (rcs_record_t *rec_p) /**< record */ +{ + JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR_EX (rec_p)); + + return (lit_magic_string_ex_id_t) rcs_record_get_field (rec_p, + RCS_MAGIC_STR_HEADER_ID_POS, + RCS_MAGIC_STR_HEADER_ID_WIDTH); +} /* rcs_record_get_magic_str_ex_id */ + +/** + * Get the number which is held by the record. + * + * @return number + */ +ecma_number_t +rcs_record_get_number (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *rec_p) /**< record */ +{ + JERRY_ASSERT (RCS_RECORD_IS_NUMBER (rec_p)); + + rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p); + rcs_iterator_skip (&it_ctx, RCS_NUMBER_HEADER_SIZE); + + ecma_number_t value; + rcs_iterator_read (&it_ctx, &value, sizeof (ecma_number_t)); + + return value; +} /* rcs_record_get_number */ + +/** + * Get the characters which are stored to the record. + * + * @return number of code units written to the buffer + */ +lit_utf8_size_t +rcs_record_get_charset (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *rec_p, /**< record */ + const lit_utf8_byte_t *buff_p, /**< output buffer */ + size_t buff_size) /**< size of the output buffer in bytes */ +{ + JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p)); + JERRY_ASSERT (buff_p && buff_size >= sizeof (lit_utf8_byte_t)); + + rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p); + rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE); + + lit_utf8_size_t str_len = rcs_record_get_length (rec_p); + lit_utf8_size_t i; + + for (i = 0; i < str_len && buff_size > 0; ++i) + { + rcs_iterator_read (&it_ctx, (void *)(buff_p + i), sizeof (lit_utf8_byte_t)); + rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t)); + buff_size -= sizeof (lit_utf8_byte_t); + } + + return i; +} /* rcs_record_get_charset */ + +/** + * Get the first record of the recordset. + * + * @return pointer of the first record of the recordset + */ +rcs_record_t * +rcs_record_get_first (rcs_record_set_t *rec_set_p) /**< recordset */ +{ + rcs_chunked_list_t::node_t *first_node_p = rec_set_p->get_first (); + + if (first_node_p == NULL) + { + return NULL; + } + + return (rcs_record_t *) rcs_get_node_data_space (rec_set_p, first_node_p); +} /* rcs_record_get_first */ + +/** + * Get record, next to the specified. + * + * @return pointer to the next record + */ +rcs_record_t * +rcs_record_get_next (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *rec_p) /**< record */ +{ + rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (rec_p); + + const uint8_t *data_space_begin_p = rcs_get_node_data_space (rec_set_p, node_p); + const size_t data_space_size = rcs_get_node_data_space_size (); + + const uint8_t *record_start_p = (const uint8_t *) rec_p; + const size_t record_size = rcs_record_get_size (rec_p); + + const size_t record_offset_in_node = (size_t) (record_start_p - data_space_begin_p); + const size_t node_size_left = data_space_size - record_offset_in_node; + + if (node_size_left > record_size) + { + return (rcs_record_t *) (record_start_p + record_size); + } + + node_p = rec_set_p->get_next (node_p); + JERRY_ASSERT (node_p != NULL || record_size == node_size_left); + + size_t record_size_left = record_size - node_size_left; + while (record_size_left >= data_space_size) + { + JERRY_ASSERT (node_p != NULL); + + node_p = rec_set_p->get_next (node_p); + record_size_left -= data_space_size; + } + + if (node_p == NULL) + { + JERRY_ASSERT (record_size_left == 0); + return NULL; + } + + return (rcs_record_t *) (rcs_get_node_data_space (rec_set_p, node_p) + record_size_left); +} /* rcs_record_get_next */ + +/** + * Compares two charset records for equality. + * + * @return true if strings inside records are equal + * false otherwise + */ +bool +rcs_record_is_equal (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *l_rec_p, /**< left record */ + rcs_record_t *r_rec_p) /**< rigth record */ +{ + size_t l_rec_length = rcs_record_get_length (l_rec_p); + size_t r_rec_length = rcs_record_get_length (r_rec_p); + + if (l_rec_length != r_rec_length) + { + return false; + } + + rcs_iterator_t l_rec_it_ctx = rcs_iterator_create (rec_set_p, l_rec_p); + rcs_iterator_t r_rec_it_ctx = rcs_iterator_create (rec_set_p, r_rec_p); + + rcs_iterator_skip (&l_rec_it_ctx, RCS_CHARSET_HEADER_SIZE); + rcs_iterator_skip (&r_rec_it_ctx, RCS_CHARSET_HEADER_SIZE); + + lit_utf8_size_t i; + for (i = 0; i < l_rec_length; ++i) + { + lit_utf8_byte_t l_chr; + lit_utf8_byte_t r_chr; + + rcs_iterator_read (&l_rec_it_ctx, &l_chr, sizeof (lit_utf8_byte_t)); + rcs_iterator_read (&r_rec_it_ctx, &r_chr, sizeof (lit_utf8_byte_t)); + + if (l_chr != r_chr) + { + return false; + } + + rcs_iterator_skip (&l_rec_it_ctx, sizeof (lit_utf8_byte_t)); + rcs_iterator_skip (&r_rec_it_ctx, sizeof (lit_utf8_byte_t)); + } + + return true; +} /* rcs_record_is_equal */ + +/** + * Compare a record with a string (which could contain '\0' characters) for equality. + * + * @return true if compared instances are equal + * false otherwise + */ +bool +rcs_record_is_equal_charset (rcs_record_set_t *rec_set_p, /**< recordset */ + rcs_record_t *rec_p, /**< record */ + const lit_utf8_byte_t *str_p, /**< string to compare with */ + lit_utf8_size_t str_size) /**< length of the string */ +{ + JERRY_ASSERT (str_p != NULL); + + size_t rec_length = rcs_record_get_length (rec_p); + + if (rec_length != str_size) + { + return false; + } + + rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p); + rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE); + + lit_utf8_size_t i; + for (i = 0; i < rec_length; ++i) + { + lit_utf8_byte_t chr; + rcs_iterator_read (&it_ctx, &chr, sizeof (lit_utf8_byte_t)); + + if (chr != str_p[i]) + { + return false; + } + + rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t)); + } + + return true; +} /* rcs_record_is_equal_charset */ diff --git a/jerry-core/rcs/rcs-records.h b/jerry-core/rcs/rcs-records.h new file mode 100644 index 0000000000..a6f059f27c --- /dev/null +++ b/jerry-core/rcs/rcs-records.h @@ -0,0 +1,169 @@ +/* Copyright 2015 Samsung Electronics Co., Ltd. + * Copyright 2015 University of Szeged + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RCS_RECORDS_H +#define RCS_RECORDS_H + +#include "ecma-globals.h" + +#define RCS_RECORD_TYPE_FIRST RCS_RECORD_TYPE_CHARSET +#define RCS_RECORD_TYPE_LAST RCS_RECORD_TYPE_NUMBER +#define RCS_RECORD_TYPE_MIN RCS_RECORD_TYPE_FREE +#define RCS_RECORD_TYPE_MAX RCS_RECORD_TYPE_NUMBER + +#define RCS_RECORD_TYPE_IS_FREE(type) ((type) == RCS_RECORD_TYPE_FREE) +#define RCS_RECORD_TYPE_IS_NUMBER(type) ((type) == RCS_RECORD_TYPE_NUMBER) +#define RCS_RECORD_TYPE_IS_CHARSET(type) ((type) == RCS_RECORD_TYPE_CHARSET) +#define RCS_RECORD_TYPE_IS_MAGIC_STR(type) ((type) == RCS_RECORD_TYPE_MAGIC_STR) +#define RCS_RECORD_TYPE_IS_MAGIC_STR_EX(type) ((type) == RCS_RECORD_TYPE_MAGIC_STR_EX) +#define RCS_RECORD_TYPE_IS_VALID(type) ((type) <= RCS_RECORD_TYPE_MAX) + +#define RCS_RECORD_IS_FREE(rec) (RCS_RECORD_TYPE_IS_FREE (rcs_record_get_type (rec))) +#define RCS_RECORD_IS_NUMBER(rec) (RCS_RECORD_TYPE_IS_NUMBER (rcs_record_get_type (rec))) +#define RCS_RECORD_IS_CHARSET(rec) (RCS_RECORD_TYPE_IS_CHARSET (rcs_record_get_type (rec))) +#define RCS_RECORD_IS_MAGIC_STR(rec) (RCS_RECORD_TYPE_IS_MAGIC_STR (rcs_record_get_type (rec))) +#define RCS_RECORD_IS_MAGIC_STR_EX(rec) (RCS_RECORD_TYPE_IS_MAGIC_STR_EX (rcs_record_get_type (rec))) + +/** + * Common header informations. + */ +#define RCS_HEADER_TYPE_POS 0u +#define RCS_HEADER_TYPE_WIDTH 4u + +#define RCS_HEADER_FIELD_BEGIN_POS (RCS_HEADER_TYPE_POS + RCS_HEADER_TYPE_WIDTH) + +/** + * Number record + * Doesn't hold any characters, holds a number. + * Numbers from source code are represented as number literals. + * + * Layout: + * ------- header ----------------------- + * type (4 bits) + * padding (12 bits) + * pointer to prev (16 bits) + * -------------------------------------- + * ecma_number_t + */ +#define RCS_NUMBER_HEADER_SIZE RCS_DYN_STORAGE_LENGTH_UNIT +#define RCS_NUMBER_HEADER_PREV_POS (RCS_HEADER_FIELD_BEGIN_POS + 12u) + +/** + * Charset record + * + * layout: + * ------- header ----------------------- + * type (4 bits) + * alignment (2 bits) + * unused (2 bits) + * hash (8 bits) + * length (16 bits) + * pointer to prev (16 bits) + * ------- characters ------------------- + * ... + * chars + * .... + * ------- alignment bytes -------------- + * unused bytes (their count is specified + * by 'alignment' field in header) + * -------------------------------------- + */ +#define RCS_CHARSET_HEADER_SIZE (RCS_DYN_STORAGE_LENGTH_UNIT + RCS_DYN_STORAGE_LENGTH_UNIT / 2) + +#define RCS_CHARSET_HEADER_ALIGN_POS RCS_HEADER_FIELD_BEGIN_POS +#define RCS_CHARSET_HEADER_ALIGN_WIDTH RCS_DYN_STORAGE_LENGTH_UNIT_LOG + +#define RCS_CHARSET_HEADER_UNUSED_POS (RCS_CHARSET_HEADER_ALIGN_POS + RCS_CHARSET_HEADER_ALIGN_WIDTH) +#define RCS_CHARSET_HEADER_UNUSED_WIDTH 2u + +#define RCS_CHARSET_HEADER_HASH_POS (RCS_CHARSET_HEADER_UNUSED_POS + RCS_CHARSET_HEADER_UNUSED_WIDTH) +#define RCS_CHARSET_HEADER_HASH_WIDTH 8u + +#define RCS_CHARSET_HEADER_LENGTH_POS (RCS_CHARSET_HEADER_HASH_POS + RCS_CHARSET_HEADER_HASH_WIDTH) +#define RCS_CHARSET_HEADER_LENGTH_WIDTH 16u + +#define RCS_CHARSET_HEADER_PREV_POS (RCS_CHARSET_HEADER_LENGTH_POS + RCS_CHARSET_HEADER_LENGTH_WIDTH) + +/** + * Magic string record + * Doesn't hold any characters. Corresponding string is identified by its id. + * + * Layout: + * ------- header ----------------------- + * type (4 bits) + * magic string id (12 bits) + * pointer to prev (16 bits) + * -------------------------------------- + */ +#define RCS_MAGIC_STR_HEADER_SIZE RCS_DYN_STORAGE_LENGTH_UNIT + +#define RCS_MAGIC_STR_HEADER_ID_POS RCS_HEADER_FIELD_BEGIN_POS +#define RCS_MAGIC_STR_HEADER_ID_WIDTH 12u + +#define RCS_MAGIC_STR_HEADER_PREV_POS (RCS_MAGIC_STR_HEADER_ID_POS + RCS_MAGIC_STR_HEADER_ID_WIDTH) + +/** + * Free record + * Doesn't hold any data. + * + * Layout: + * ------- header ----------------------- + * type (4 bits) + * length (12 bits) + * pointer to prev (16 bits) + * -------------------------------------- + */ +#define RCS_FREE_HEADER_SIZE RCS_DYN_STORAGE_LENGTH_UNIT + +#define RCS_FREE_HEADER_LENGTH_POS RCS_HEADER_FIELD_BEGIN_POS +#define RCS_FREE_HEADER_LENGTH_WIDTH (14u - RCS_DYN_STORAGE_LENGTH_UNIT_LOG) + +#define RCS_FREE_HEADER_PREV_POS (RCS_FREE_HEADER_LENGTH_POS + RCS_FREE_HEADER_LENGTH_WIDTH) + +/* + * Setters + */ +extern void rcs_record_set_type (rcs_record_t *, rcs_record_type_t); +extern void rcs_record_set_prev (rcs_record_set_t *, rcs_record_t *, rcs_record_t *); +extern void rcs_record_set_size (rcs_record_t *, size_t); +extern void rcs_record_set_alignment_bytes_count (rcs_record_t *, size_t); +extern void rcs_record_set_hash (rcs_record_t *, lit_string_hash_t); +extern void rcs_record_set_charset (rcs_record_set_t *, rcs_record_t *, const lit_utf8_byte_t *, lit_utf8_size_t); +extern void rcs_record_set_magic_str_id (rcs_record_t *, lit_magic_string_id_t); +extern void rcs_record_set_magic_str_ex_id (rcs_record_t *, lit_magic_string_ex_id_t); + +/* + * Getters + */ +extern rcs_record_type_t rcs_record_get_type (rcs_record_t *); +extern rcs_record_t *rcs_record_get_prev (rcs_record_set_t *, rcs_record_t *); +extern size_t rcs_record_get_size (rcs_record_t *); +extern size_t rcs_header_get_size (rcs_record_t *); +extern size_t rcs_record_get_alignment_bytes_count (rcs_record_t *); +extern lit_string_hash_t rcs_record_get_hash (rcs_record_t *); +extern lit_utf8_size_t rcs_record_get_length (rcs_record_t *); +extern lit_utf8_size_t rcs_record_get_charset (rcs_record_set_t *, rcs_record_t *, const lit_utf8_byte_t *, size_t); +extern lit_magic_string_id_t rcs_record_get_magic_str_id (rcs_record_t *); +extern lit_magic_string_ex_id_t rcs_record_get_magic_str_ex_id (rcs_record_t *); +extern ecma_number_t rcs_record_get_number (rcs_record_set_t *, rcs_record_t *); + +extern rcs_record_t *rcs_record_get_first (rcs_record_set_t *); +extern rcs_record_t *rcs_record_get_next (rcs_record_set_t *, rcs_record_t *); + +extern bool rcs_record_is_equal (rcs_record_set_t *, rcs_record_t *, rcs_record_t *); +extern bool rcs_record_is_equal_charset (rcs_record_set_t *, rcs_record_t *, const lit_utf8_byte_t *, lit_utf8_size_t); + +#endif /* !RCS_RECORDS_H */ diff --git a/jerry-core/rcs/rcs-recordset.cpp b/jerry-core/rcs/rcs-recordset.cpp deleted file mode 100644 index 145f2dccbe..0000000000 --- a/jerry-core/rcs/rcs-recordset.cpp +++ /dev/null @@ -1,864 +0,0 @@ -/* Copyright 2015 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "rcs-chunked-list.h" -#include "rcs-recordset.h" - -/** \addtogroup recordset Recordset - * @{ - * - * Non-contiguous container abstraction with iterator. - * - * @{ - */ - -/** - * Get the record's type identifier - * - * @return record type identifier - */ -rcs_record_t::type_t -rcs_recordset_t::record_t::get_type (void) -const -{ - JERRY_STATIC_ASSERT (sizeof (type_t) * JERRY_BITSINBYTE >= _type_field_width); - - return (type_t) get_field (_type_field_pos, _type_field_width); -} /* rcs_recordset_t::record_t::get_type */ - -/** - * Set the record's type identifier - */ -void -rcs_recordset_t::record_t::set_type (rcs_record_t::type_t type) /**< record type identifier */ -{ - set_field (_type_field_pos, _type_field_width, type); -} /* rcs_recordset_t::record_t::set_type */ - -/** - * Compress pointer to extended compressed pointer - * - * @return dynamic storage-specific extended compressed pointer - */ -rcs_cpointer_t -rcs_recordset_t::record_t::cpointer_t::compress (rcs_record_t *pointer) /**< pointer to compress */ -{ - rcs_cpointer_t cpointer; - - cpointer.packed_value = 0; - - uintptr_t base_pointer = JERRY_ALIGNDOWN ((uintptr_t) pointer, MEM_ALIGNMENT); - - if ((void *) base_pointer == NULL) - { - cpointer.value.base_cp = MEM_CP_NULL; - } - else - { - cpointer.value.base_cp = mem_compress_pointer ((void *) base_pointer) & MEM_CP_MASK; - } - -#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG - /* - * If alignment of a unit in recordset storage is less than required by MEM_ALIGNMENT_LOG, - * then mem_cpointer_t can't store pointer to the unit, and so, rcs_cpointer_t stores - * mem_cpointer_t to block, aligned to MEM_ALIGNMENT, and also extension with difference - * between positions of the MEM_ALIGNMENT-aligned block and the unit. - */ - uintptr_t diff = (uintptr_t) pointer - base_pointer; - - JERRY_ASSERT (diff < MEM_ALIGNMENT); - JERRY_ASSERT (jrt_extract_bit_field (diff, 0, RCS_DYN_STORAGE_LENGTH_UNIT_LOG) == 0); - - uintptr_t ext_part = (uintptr_t) jrt_extract_bit_field (diff, - RCS_DYN_STORAGE_LENGTH_UNIT_LOG, - MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG); - - cpointer.value.ext = ext_part & ((1ull << (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG)) - 1); -#endif /* MEM_ALIGNMENT > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */ - - JERRY_ASSERT (decompress (cpointer) == pointer); - - return cpointer; -} /* rcs_recordset_t::record_t::cpointer_t::compress */ - -/** - * Decompress extended compressed pointer - * - * @return decompressed pointer - */ -rcs_record_t* -rcs_recordset_t::record_t::cpointer_t::decompress (rcs_cpointer_t compressed_pointer) /**< recordset-specific - * compressed pointer */ -{ - uint8_t* base_pointer; - if (compressed_pointer.value.base_cp == MEM_CP_NULL) - { - base_pointer = NULL; - } - else - { - base_pointer = (uint8_t*) mem_decompress_pointer (compressed_pointer.value.base_cp); - } - - uintptr_t diff = 0; - -#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG - /* - * See also: - * rcs_recordset_t::record_t::cpointer_t::compress - */ - - diff = (uintptr_t) compressed_pointer.value.ext << RCS_DYN_STORAGE_LENGTH_UNIT_LOG; -#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */ - - rcs_record_t *rec_p = (rcs_record_t *) (base_pointer + diff); - - return rec_p; -} /* rcs_recordset_t::record_t::cpointer_t::decompress */ - -/** - * Create NULL compressed pointer - * - * @return NULL compressed pointer - */ -rcs_cpointer_t -rcs_recordset_t::record_t::cpointer_t::null_cp () -{ - rcs_cpointer_t cp; - cp.packed_value = MEM_CP_NULL; - return cp; -} /* rcs_recordset_t::record_t::cpointer_t::null_cp */ - -/** - * Assert that 'this' value points to correct record - */ -void -rcs_recordset_t::record_t::check_this (void) -const -{ - JERRY_ASSERT (this != NULL); - - uintptr_t ptr = (uintptr_t) this; - - JERRY_ASSERT (JERRY_ALIGNUP (ptr, RCS_DYN_STORAGE_LENGTH_UNIT) == ptr); -} /* rcs_recordset_t::record_t::check_this */ - -/** - * Get value of the record's field with specified offset and width - * - * @return field's 32-bit unsigned integer value - */ -uint32_t -rcs_recordset_t::record_t::get_field (uint32_t field_pos, /**< offset, in bits */ - uint32_t field_width) /**< width, in bits */ -const -{ - check_this (); - - JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT); - JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE); - - uint32_t value = *reinterpret_cast (this); - return (uint32_t) jrt_extract_bit_field (value, field_pos, field_width); -} /* rcs_recordset_t::record_t::get_field */ - -/** - * Set value of the record's field with specified offset and width - */ -void -rcs_recordset_t::record_t::set_field (uint32_t field_pos, /**< offset, in bits */ - uint32_t field_width, /**< width, in bits */ - size_t value) /**< 32-bit unsigned integer value */ -{ - check_this (); - - JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT); - JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE); - - uint32_t prev_value = *reinterpret_cast (this); - *reinterpret_cast (this) = (uint32_t) jrt_set_bit_field_value (prev_value, - value, - field_pos, - field_width); -} /* rcs_recordset_t::record_t::set_field */ - -/** - * Get value of the record's pointer field with specified offset and width - * - * @return pointer to record - */ -rcs_record_t* -rcs_recordset_t::record_t::get_pointer (uint32_t field_pos, /**< offset, in bits */ - uint32_t field_width) /**< width, in bits */ -const -{ - cpointer_t cpointer; - - uint16_t value = (uint16_t) get_field (field_pos, field_width); - - JERRY_ASSERT (sizeof (cpointer) == sizeof (cpointer.value)); - JERRY_ASSERT (sizeof (value) == sizeof (cpointer.value)); - - cpointer.packed_value = value; - - return cpointer_t::decompress (cpointer); -} /* rcs_recordset_t::record_t::get_pointer */ - -/** - * Set value of the record's pointer field with specified offset and width - */ -void -rcs_recordset_t::record_t::set_pointer (uint32_t field_pos, /**< offset, in bits */ - uint32_t field_width, /**< width, in bits */ - rcs_record_t* pointer_p) /**< pointer to a record */ -{ - cpointer_t cpointer = cpointer_t::compress (pointer_p); - - set_field (field_pos, field_width, cpointer.packed_value); -} /* rcs_recordset_t::record_t::set_pointer */ - -/** - * Initialize record in specified place, and, if there is free space - * before next record, initialize free record for the space - */ -void -rcs_recordset_t::alloc_record_in_place (rcs_record_t* place_p, /**< where to initialize record */ - size_t free_size, /**< size of free part between allocated record - * and next allocated record */ - rcs_record_t* next_record_p) /**< next allocated record */ -{ - const size_t node_data_space_size = get_node_data_space_size (); - - if (next_record_p != NULL) - { - if (free_size == 0) - { - set_prev (next_record_p, place_p); - } - else - { - rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (next_record_p); - uint8_t* node_data_space_p = get_node_data_space (node_p); - - JERRY_ASSERT ((uint8_t*) next_record_p < node_data_space_p + node_data_space_size); - - rcs_record_t* free_rec_p; - - if ((uint8_t*) next_record_p >= node_data_space_p + free_size) - { - free_rec_p = (rcs_record_t*) ((uint8_t*) next_record_p - free_size); - } - else - { - size_t size_passed_back = (size_t) ((uint8_t*) next_record_p - node_data_space_p); - JERRY_ASSERT (size_passed_back < free_size && size_passed_back + node_data_space_size > free_size); - - node_p = _chunk_list.get_prev (node_p); - node_data_space_p = get_node_data_space (node_p); - - free_rec_p = (rcs_record_t*) (node_data_space_p + node_data_space_size - \ - (free_size - size_passed_back)); - } - - init_free_record (free_rec_p, free_size, place_p); - } - } - else if (free_size != 0) - { - rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (place_p); - JERRY_ASSERT (node_p != NULL); - - rcs_chunked_list_t::node_t* next_node_p = _chunk_list.get_next (node_p); - - while (next_node_p != NULL) - { - node_p = next_node_p; - - next_node_p = _chunk_list.get_next (node_p); - } - - uint8_t* node_data_space_p = get_node_data_space (node_p); - const size_t node_data_space_size = get_node_data_space_size (); - - rcs_record_t* free_rec_p = (rcs_record_t*) (node_data_space_p + node_data_space_size \ - - free_size); - init_free_record (free_rec_p, free_size, place_p); - } -} /* rcs_recordset_t::alloc_record_in_place */ - -/** - * Initialize specified record as free record - */ -void -rcs_recordset_t::init_free_record (rcs_record_t *rec_p, /**< record to init as free record */ - size_t size, /**< size, including header */ - rcs_record_t *prev_rec_p) /**< previous record (or NULL) */ -{ - rcs_free_record_t *free_rec_p = static_cast (rec_p); - - free_rec_p->set_type (_free_record_type_id); - free_rec_p->set_size (size); - free_rec_p->set_prev (prev_rec_p); -} /* rcs_recordset_t::init_free_record */ - -/** - * Check if the record is free record - */ -bool -rcs_recordset_t::is_record_free (rcs_record_t *record_p) /**< a record */ -{ - JERRY_ASSERT (record_p != NULL); - - return (record_p->get_type () == _free_record_type_id); -} /* rcs_recordset_t::is_record_free */ - -/** - * Get the node's data space - * - * @return pointer to beginning of the node's data space - */ -uint8_t * -rcs_recordset_t::get_node_data_space (rcs_chunked_list_t::node_t *node_p) /**< the node */ -const -{ - uintptr_t unaligned_data_space_beg = (uintptr_t) _chunk_list.get_node_data_space (node_p); - uintptr_t aligned_data_space_beg = JERRY_ALIGNUP (unaligned_data_space_beg, RCS_DYN_STORAGE_LENGTH_UNIT); - - JERRY_ASSERT (unaligned_data_space_beg + rcs_chunked_list_t::get_node_data_space_size () - == aligned_data_space_beg + rcs_recordset_t::get_node_data_space_size ()); - - return (uint8_t *) aligned_data_space_beg; -} /* rcs_recordset_t::get_node_data_space */ - -/** - * Get size of a node's data space - * - * @return size - */ -size_t -rcs_recordset_t::get_node_data_space_size (void) -{ - return JERRY_ALIGNDOWN (rcs_chunked_list_t::get_node_data_space_size (), RCS_DYN_STORAGE_LENGTH_UNIT); -} /* rcs_recordset_t::get_node_data_space_size */ - -/** - * Allocate record of specified size - * - * @return record identifier - */ -rcs_record_t* -rcs_recordset_t::alloc_space_for_record (size_t bytes, /**< size */ - rcs_record_t** out_prev_rec_p) /**< out: pointer to record, previous - * to the allocated, or NULL if the allocated - * record is the first */ -{ - assert_state_is_correct (); - - JERRY_ASSERT (JERRY_ALIGNUP (bytes, RCS_DYN_STORAGE_LENGTH_UNIT) == bytes); - JERRY_ASSERT (out_prev_rec_p != NULL); - - const size_t node_data_space_size = get_node_data_space_size (); - - *out_prev_rec_p = NULL; - - for (rcs_record_t *rec_p = get_first (); - rec_p != NULL; - *out_prev_rec_p = rec_p, rec_p = get_next (rec_p)) - { - if (is_record_free (rec_p)) - { - size_t record_size = get_record_size (rec_p); - - rcs_record_t* next_rec_p = get_next (rec_p); - - if (record_size >= bytes) - { - /* record size is sufficient */ - alloc_record_in_place (rec_p, record_size - bytes, next_rec_p); - - return rec_p; - } - else - { - rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (rec_p); - uint8_t* node_data_space_p = get_node_data_space (node_p); - uint8_t* node_data_space_end_p = node_data_space_p + node_data_space_size; - - uint8_t* rec_space_p = (uint8_t*) rec_p; - - if (rec_space_p + record_size >= node_data_space_end_p) - { - /* record lies up to end of node's data space size, - * and, so, can be extended up to necessary size */ - - while (record_size < bytes) - { - node_p = _chunk_list.insert_new (node_p); - - record_size += node_data_space_size; - } - - alloc_record_in_place (rec_p, record_size - bytes, next_rec_p); - - return rec_p; - } - } - - if (next_rec_p == NULL) - { - /* in the case, there are no more records in the storage, - * so, we should append new record */ - break; - } - else - { - JERRY_ASSERT (!is_record_free (rec_p)); - } - } - } - - /* free record of sufficient size was not found */ - - rcs_chunked_list_t::node_t *node_p = _chunk_list.append_new (); - rcs_record_t* new_rec_p = (rcs_record_t*) get_node_data_space (node_p); - - size_t allocated_size = node_data_space_size; - - while (allocated_size < bytes) - { - allocated_size += node_data_space_size; - _chunk_list.append_new (); - } - - alloc_record_in_place (new_rec_p, allocated_size - bytes, NULL); - - return new_rec_p; -} /* rcs_recordset_t::alloc_space_for_record */ - -/** - * Free specified record - */ -void -rcs_recordset_t::free_record (rcs_record_t* record_p) /**< record to free */ -{ - JERRY_ASSERT (record_p != NULL); - - assert_state_is_correct (); - - rcs_record_t *prev_rec_p = get_prev (record_p); - - // make record free - init_free_record (record_p, get_record_size (record_p), prev_rec_p); - - // merge adjacent free records, if there are any, - // and free nodes of chunked list that became unused - rcs_record_t *rec_from_p = record_p, *rec_to_p = get_next (record_p); - - if (prev_rec_p != NULL - && is_record_free (prev_rec_p)) - { - rec_from_p = prev_rec_p; - - prev_rec_p = get_prev (rec_from_p); - } - - if (rec_to_p != NULL - && is_record_free (rec_to_p)) - { - rec_to_p = get_next (rec_to_p); - } - - JERRY_ASSERT (rec_from_p != NULL && is_record_free (rec_from_p)); - JERRY_ASSERT (rec_to_p == NULL || !is_record_free (rec_to_p)); - - rcs_chunked_list_t::node_t *node_from_p = _chunk_list.get_node_from_pointer (rec_from_p); - rcs_chunked_list_t::node_t *node_to_p; - - if (rec_to_p == NULL) - { - node_to_p = NULL; - } - else - { - node_to_p = _chunk_list.get_node_from_pointer (rec_to_p); - } - - const size_t node_data_space_size = get_node_data_space_size (); - - uint8_t* rec_from_beg_p = (uint8_t*) rec_from_p; - uint8_t* rec_to_beg_p = (uint8_t*) rec_to_p; - size_t free_size; - - if (node_from_p == node_to_p) - { - JERRY_ASSERT (rec_from_beg_p + get_record_size (rec_from_p) <= rec_to_beg_p); - - free_size = (size_t) (rec_to_beg_p - rec_from_beg_p); - } - else - { - for (rcs_chunked_list_t::node_t *iter_node_p = _chunk_list.get_next (node_from_p), *iter_next_node_p; - iter_node_p != node_to_p; - iter_node_p = iter_next_node_p) - { - iter_next_node_p = _chunk_list.get_next (iter_node_p); - - _chunk_list.remove (iter_node_p); - } - - JERRY_ASSERT (_chunk_list.get_next (node_from_p) == node_to_p); - - size_t node_from_space = (size_t) (get_node_data_space (node_from_p) + - node_data_space_size - rec_from_beg_p); - size_t node_to_space = (size_t) (node_to_p != NULL - ? rec_to_beg_p - get_node_data_space (node_to_p) - : 0); - - free_size = node_from_space + node_to_space; - } - - init_free_record (rec_from_p, free_size, prev_rec_p); - - if (rec_to_p != NULL) - { - set_prev (rec_to_p, rec_from_p); - } - else if (prev_rec_p == NULL) - { - JERRY_ASSERT (node_to_p == NULL); - - _chunk_list.remove (node_from_p); - - JERRY_ASSERT (_chunk_list.get_first () == NULL); - } - - assert_state_is_correct (); -} /* rcs_recordset_t::free_record */ - -/** - * Get first record - * - * @return pointer of the first record of the recordset - */ -rcs_record_t* -rcs_recordset_t::get_first (void) -{ - rcs_chunked_list_t::node_t *first_node_p = _chunk_list.get_first (); - - if (first_node_p == NULL) - { - return NULL; - } - else - { - return (rcs_record_t*) get_node_data_space (first_node_p); - } -} /* rcs_recordset_t::get_first */ - -/** - * Get record, previous to the specified - * - * @return pointer to the previous record - */ -rcs_record_t* -rcs_recordset_t::get_prev (rcs_record_t* rec_p) /**< record */ -{ - JERRY_ASSERT (rec_p->get_type () == _free_record_type_id); - - rcs_free_record_t *free_rec_p = static_cast (rec_p); - - return free_rec_p->get_prev (); -} /* rcs_recordset_t::get_prev */ - -/** - * Get record, next to the specified - * - * @return pointer to the next record - */ -rcs_record_t* -rcs_recordset_t::get_next (rcs_record_t* rec_p) /**< record */ -{ - rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (rec_p); - - const uint8_t* data_space_begin_p = get_node_data_space (node_p); - const size_t data_space_size = get_node_data_space_size (); - - const uint8_t* record_start_p = (const uint8_t*) rec_p; - size_t record_size = get_record_size (rec_p); - - size_t record_offset_in_node = (size_t) (record_start_p - data_space_begin_p); - size_t node_size_left = data_space_size - record_offset_in_node; - - if (node_size_left > record_size) - { - return (rcs_record_t*) (record_start_p + record_size); - } - else - { - node_p = _chunk_list.get_next (node_p); - JERRY_ASSERT (node_p != NULL || record_size == node_size_left); - - size_t record_size_left = record_size - node_size_left; - - while (record_size_left >= data_space_size) - { - JERRY_ASSERT (node_p != NULL); - node_p = _chunk_list.get_next (node_p); - - record_size_left -= data_space_size; - } - - if (node_p == NULL) - { - JERRY_ASSERT (record_size_left == 0); - - return NULL; - } - else - { - return (rcs_record_t*) (get_node_data_space (node_p) + record_size_left); - } - } -} /* rcs_recordset_t::get_next */ - -/** - * Set previous record - */ -void -rcs_recordset_t::set_prev (rcs_record_t* rec_p, /**< record to set previous for */ - rcs_record_t *prev_rec_p) /**< previous record */ -{ - JERRY_ASSERT (rec_p->get_type () == _free_record_type_id); - - rcs_free_record_t *free_rec_p = static_cast (rec_p); - - free_rec_p->set_prev (prev_rec_p); -} /* rcs_recordset_t::set_prev */ - -/** - * Get size of the record - */ -size_t -rcs_recordset_t::get_record_size (rcs_record_t* rec_p) /**< record */ -{ - JERRY_ASSERT (rec_p->get_type () == _free_record_type_id); - - rcs_free_record_t *free_rec_p = static_cast (rec_p); - - return free_rec_p->get_size (); -} /* rcs_recordset_t::get_record_size */ - -/** - * Assert that recordset state is correct - */ -void -rcs_recordset_t::assert_state_is_correct (void) -{ -#ifndef JERRY_DISABLE_HEAVY_DEBUG - size_t node_size_sum = 0; - size_t record_size_sum = 0; - - rcs_record_t* last_record_p = NULL; - - for (rcs_record_t* rec_p = get_first (), *next_rec_p; - rec_p != NULL; - last_record_p = rec_p, rec_p = next_rec_p) - { - JERRY_ASSERT (get_record_size (rec_p) > 0); - record_size_sum += get_record_size (rec_p); - - rcs_chunked_list_t::node_t *node_p = _chunk_list.get_node_from_pointer (rec_p); - - next_rec_p = get_next (rec_p); - - rcs_chunked_list_t::node_t *next_node_p; - if (next_rec_p == NULL) - { - next_node_p = NULL; - } - else - { - next_node_p = _chunk_list.get_node_from_pointer (next_rec_p); - } - - while (node_p != next_node_p) - { - node_p = _chunk_list.get_next (node_p); - node_size_sum += get_node_data_space_size (); - } - } - - JERRY_ASSERT (node_size_sum == record_size_sum); - - record_size_sum = 0; - for (rcs_record_t* rec_p = last_record_p; - rec_p != NULL; - rec_p = get_prev (rec_p)) - { - record_size_sum += get_record_size (rec_p); - } - - JERRY_ASSERT (node_size_sum == record_size_sum); -#endif /* !JERRY_DISABLE_HEAVY_DEBUG */ -} /* rcs_recordset_t::assert_state_is_correct */ - -/** - * Perform general access to the record - * - * Warning: This function is implemented in assumption that `size` is not more than `2 * node_data_space_size`. - */ -void -rcs_record_iterator_t::access (access_t access_type, /**< type of access: read, write or skip */ - void *data, /**< in/out data to read or write */ - size_t size) /**< size of the data in bytes */ -{ - const size_t node_data_space_size = _recordset_p->get_node_data_space_size (); - JERRY_ASSERT (2 * node_data_space_size >= size); - const size_t record_size = _recordset_p->get_record_size (_record_start_p); - - JERRY_ASSERT (!finished ()); - - rcs_chunked_list_t::node_t *current_node_p = _recordset_p->_chunk_list.get_node_from_pointer (_current_pos_p); - uint8_t *current_node_data_space_p = _recordset_p->get_node_data_space (current_node_p); - size_t left_in_node = node_data_space_size - (size_t)(_current_pos_p - current_node_data_space_p); - - JERRY_ASSERT (_current_offset + size <= record_size); - - /* - * Read the data and increase the current position pointer. - */ - if (left_in_node >= size) - { - /* all data is placed inside single node */ - if (access_type == ACCESS_READ) - { - memcpy (data, _current_pos_p, size); - } - else if (access_type == ACCESS_WRITE) - { - memcpy (_current_pos_p, data, size); - } - else - { - JERRY_ASSERT (access_type == ACCESS_SKIP); - - if (left_in_node > size) - { - _current_pos_p += size; - } - else if (_current_offset + size < record_size) - { - current_node_p = _recordset_p->_chunk_list.get_next (current_node_p); - JERRY_ASSERT (current_node_p); - _current_pos_p = _recordset_p->get_node_data_space (current_node_p); - } - else - { - JERRY_ASSERT (_current_offset + size == record_size); - } - } - } - else - { - /* data is distributed between two nodes */ - size_t first_chunk_size = node_data_space_size - (size_t) (_current_pos_p - current_node_data_space_p); - - if (access_type == ACCESS_READ) - { - memcpy (data, _current_pos_p, first_chunk_size); - } - else if (access_type == ACCESS_WRITE) - { - memcpy (_current_pos_p, data, first_chunk_size); - } - - rcs_chunked_list_t::node_t *next_node_p = _recordset_p->_chunk_list.get_next (current_node_p); - JERRY_ASSERT (next_node_p != NULL); - uint8_t *next_node_data_space_p = _recordset_p->get_node_data_space (next_node_p); - - if (access_type == ACCESS_READ) - { - memcpy ((uint8_t *)data + first_chunk_size, next_node_data_space_p, size - first_chunk_size); - } - else if (access_type == ACCESS_WRITE) - { - memcpy (next_node_data_space_p, (uint8_t *)data + first_chunk_size, size - first_chunk_size); - } - else - { - JERRY_ASSERT (access_type == ACCESS_SKIP); - - _current_pos_p = next_node_data_space_p + size - first_chunk_size; - } - } - - /* check if we reached the end */ - if (access_type == ACCESS_SKIP) - { - _current_offset += size; - JERRY_ASSERT (_current_offset <= record_size); - - if (_current_offset == record_size) - { - _current_pos_p = NULL; - _current_offset = 0; - } - } -} /* rcs_record_iterator_t::access */ - -/** - * Get size of the free record - */ -size_t -rcs_free_record_t::get_size (void) -const -{ - return get_field (_length_field_pos, _length_field_width) * RCS_DYN_STORAGE_LENGTH_UNIT; -} /* rcs_free_record_t::get_size */ - -/** - * Set size of the free record - */ -void -rcs_free_record_t::set_size (size_t size) /**< size to set */ -{ - JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size); - - set_field (_length_field_pos, _length_field_width, size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG); -} /* rcs_free_record_t::set_size */ - -/** - * Get previous record for the free record - */ -rcs_record_t* -rcs_free_record_t::get_prev (void) -const -{ - return get_pointer (_prev_field_pos, _prev_field_width); -} /* rcs_free_record_t::get_prev */ - -/** - * Set previous record for the free record - */ -void -rcs_free_record_t::set_prev (rcs_record_t* prev_rec_p) /**< previous record to set */ -{ - set_pointer (_prev_field_pos, _prev_field_width, prev_rec_p); -} /* rcs_free_record_t::set_prev */ - -/** - * @} - */ diff --git a/jerry-core/rcs/rcs-recordset.h b/jerry-core/rcs/rcs-recordset.h deleted file mode 100644 index f6e7fed97a..0000000000 --- a/jerry-core/rcs/rcs-recordset.h +++ /dev/null @@ -1,383 +0,0 @@ -/* Copyright 2015 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RCS_RECORDSET_H -#define RCS_RECORDSET_H - -#include - -#include "jrt.h" -#include "jrt-bit-fields.h" -#include "mem-allocator.h" -#include "rcs-chunked-list.h" - -/** \addtogroup recordset Recordset - * @{ - * - * Non-contiguous container abstraction with iterator. - * - * @{ - */ - -/** - * Logarithm of a dynamic storage unit alignment - */ -#define RCS_DYN_STORAGE_LENGTH_UNIT_LOG (2u) - -/** - * Unit of length - */ -#define RCS_DYN_STORAGE_LENGTH_UNIT ((size_t) (1ull << RCS_DYN_STORAGE_LENGTH_UNIT_LOG)) - -/** - * Dynamic storage - * - * Note: - * Static C++ constructors / desctructors are supposed to be not supported. - * So, initialization / destruction is implemented through init / finalize - * static functions. - */ -class rcs_recordset_t -{ -public: - /* Constructor */ - void init (void) - { - _chunk_list.init (); - - JERRY_ASSERT (get_node_data_space_size () % RCS_DYN_STORAGE_LENGTH_UNIT == 0); - } /* init */ - - /* Destructor */ - void finalize (void) - { - _chunk_list.free (); - } /* finalize */ - - /* Free memory occupied by the dynamic storage */ - void cleanup (void) - { - _chunk_list.cleanup (); - } /* cleanup */ - - /** - * Record type - */ - class record_t - { - public: - typedef uint8_t type_t; - - type_t get_type (void) const; - void set_type (type_t); - - /** - * Dynamic storage-specific extended compressed pointer - * - * Note: - * the pointer can represent addresses aligned by RCS_DYN_STORAGE_LENGTH_UNIT, - * while mem_cpointer_t can only represent addresses aligned by MEM_ALIGNMENT. - */ - struct cpointer_t - { - static const uint32_t bit_field_width = MEM_CP_WIDTH + MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG; - - union - { - struct - { - mem_cpointer_t base_cp : MEM_CP_WIDTH; /**< pointer to base of addressed area */ -#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG - uint16_t ext : (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG); /**< extension of the basic - * compressed pointer - * used for more detailed - * addressing */ -#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */ - } value; - uint16_t packed_value; - }; - - static cpointer_t compress (record_t *); - static record_t *decompress (cpointer_t); - - static cpointer_t null_cp (); - - static const int conval = 3; - }; - - private: - /** - * Offset of 'type' field, in bits - */ - static constexpr uint32_t _type_field_pos = 0u; - - /** - * Width of 'type' field, in bits - */ - static constexpr uint32_t _type_field_width = 4u; - - protected: - void check_this (void) const; - - uint32_t get_field (uint32_t, uint32_t) const; - void set_field (uint32_t, uint32_t, size_t); - - record_t *get_pointer (uint32_t, uint32_t) const; - void set_pointer (uint32_t, uint32_t, record_t *); - - /** - * Offset of a derived record's fields, in bits - */ - static constexpr uint32_t _fields_offset_begin = _type_field_pos + _type_field_width; - }; - - record_t *get_first (void); - record_t *get_next (record_t *); - -private: - friend class rcs_record_iterator_t; - - /** - * Type identifier for free record - */ - static const record_t::type_t _free_record_type_id = 0; - - /** - * Chunked list used for memory allocation - */ - rcs_chunked_list_t _chunk_list; - - void alloc_record_in_place (record_t *, size_t, record_t *); - - void init_free_record (record_t *, size_t, record_t *); - bool is_record_free (record_t *); - - uint8_t *get_node_data_space (rcs_chunked_list_t::node_t *) const; - static size_t get_node_data_space_size (void); -protected: - /** - * First type identifier that can be used for storage-specific record types - */ - static const record_t::type_t _first_type_id = _free_record_type_id + 1; - - /** - * Allocate new record of specified type - * - * @return pointer to the new record - */ - template< - typename T, /**< type of record structure */ - typename ... SizeArgs> /**< type of arguments of T::size */ - T *alloc_record (record_t::type_t type, /**< record's type identifier */ - SizeArgs ... size_args) /**< arguments of T::size */ - { - JERRY_ASSERT (type >= _first_type_id); - - size_t size = T::size (size_args...); - - record_t *prev_rec_p; - T *rec_p = static_cast (alloc_space_for_record (size, &prev_rec_p)); - - rec_p->set_type (type); - rec_p->set_size (size); - rec_p->set_prev (prev_rec_p); - - assert_state_is_correct (); - - return rec_p; - } /* alloc_record */ - - record_t *alloc_space_for_record (size_t, record_t **); - void free_record (record_t *); - - virtual record_t *get_prev (record_t *); - - virtual void set_prev (record_t *, record_t *); - - virtual size_t get_record_size (record_t *); - - void assert_state_is_correct (void); -}; /* rcs_recordset_t */ - -/** - * Record type - */ -typedef rcs_recordset_t::record_t rcs_record_t; - -/** - * Recordset-specific compressed pointer type - */ -typedef rcs_record_t::cpointer_t rcs_cpointer_t; - -/** - * Record iterator - */ -class rcs_record_iterator_t -{ -public: - /** - * Constructor - */ - rcs_record_iterator_t (rcs_recordset_t *rcs_p, /**< recordset */ - rcs_record_t *rec_p) /**< record which should belong to the recordset */ - { - _record_start_p = rec_p; - _recordset_p = rcs_p; - - reset (); - } /* rcs_record_iterator_t */ - - /** - * Constructor - */ - rcs_record_iterator_t (rcs_recordset_t *rcs_p, /**< recordset */ - rcs_cpointer_t rec_ext_cp) /**< compressed pointer to the record */ - { - _record_start_p = rcs_cpointer_t::decompress (rec_ext_cp); - _recordset_p = rcs_p; - - reset (); - } /* rcs_record_iterator_t */ - -protected: - /** - * Types of access - */ - typedef enum - { - ACCESS_WRITE, /**< If access_type == ACCESS_WRITE, - * write 'size' bytes from 'data' buffer to the record. */ - ACCESS_READ, /**< If access_type == ACCESS_READ, - * read 'size' bytes from the record and write to the 'data' buffer. */ - ACCESS_SKIP /**< If access_type == ACCESS_SKIP, - * increment current position so that 'size' bytes would be skipped. */ - } access_t; - - void access (access_t, void *, size_t); - -public: - /** - * Read value of type T from the record. - * After reading iterator doesn't change its position. - * - * @return read value - */ - template T read (void) - { - T data; - access (ACCESS_READ, &data, sizeof (T)); - return data; - } /* read */ - - /** - * Write value of type T to the record. - * After writing iterator doesn't change its position. - */ - template void write (T value) /**< value to write */ - { - access (ACCESS_WRITE, &value, sizeof (T)); - } /* write */ - - /** - * Increment current position to skip T value in the record. - */ - template void skip () - { - access (ACCESS_SKIP, NULL, sizeof (T)); - } /* skip */ - - /** - * Increment current position to skip 'size' bytes. - */ - void skip (size_t size) /**< number of bytes to skip */ - { - if (size) - { - access (ACCESS_SKIP, NULL, size); - } - } /* skip */ - - /** - * Check if the end of the record was reached. - * - * @return true if the whole record was iterated - * false otherwise - */ - bool finished () - { - return _current_pos_p == NULL; - } /* finished */ - - /** - * Reset the iterator, so that it points to the beginning of the record - */ - void reset () - { - _current_pos_p = (uint8_t *)_record_start_p; - _current_offset = 0; - } /* reset */ - -private: - rcs_record_t *_record_start_p; /**< start of current record */ - uint8_t *_current_pos_p; /**< pointer to current offset in current record */ - size_t _current_offset; /**< current offset */ - rcs_recordset_t *_recordset_p; /**< recordset containing the record */ -}; /* rcs_record_iterator_t */ - -/** - * Free record layout description - */ -class rcs_free_record_t : public rcs_record_t -{ -public: - size_t get_size (void) const; - void set_size (size_t); - - rcs_record_t *get_prev (void) const; - void set_prev (rcs_record_t *); -private: - /** - * Offset of 'length' field, in bits - */ - static constexpr uint32_t _length_field_pos = _fields_offset_begin; - - /** - * Width of 'length' field, in bits - */ - static constexpr uint32_t _length_field_width = 14u - RCS_DYN_STORAGE_LENGTH_UNIT_LOG; - - /** - * Offset of 'previous record' field, in bits - */ - static constexpr uint32_t _prev_field_pos = _length_field_pos + _length_field_width; - - /** - * Width of 'previous record' field, in bits - */ - static constexpr uint32_t _prev_field_width = rcs_cpointer_t::bit_field_width; - - /** - * Free record should be be placeable at any free space unit of recordset, - * and so its size should be less than minimal size of a free space unit - * that is RCS_DYN_STORAGE_LENGTH_UNIT bytes. - */ - JERRY_STATIC_ASSERT (_prev_field_pos + _prev_field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE); -}; - -/** - * @} - */ - -#endif /* RCS_RECORDSET_H */ diff --git a/jerry-core/vm/opcodes.cpp b/jerry-core/vm/opcodes.cpp index 31c5267021..8285370691 100644 --- a/jerry-core/vm/opcodes.cpp +++ b/jerry-core/vm/opcodes.cpp @@ -16,8 +16,10 @@ #include "bytecode-data.h" #include "jrt.h" +#include "jrt-bit-fields.h" #include "opcodes.h" #include "opcodes-ecma-support.h" +#include "rcs-records.h" /** * Note: @@ -112,10 +114,10 @@ opfunc_assignment (vm_instr_t instr, /**< instruction */ lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (src_val_descr, frame_ctx_p->bytecode_header_p, frame_ctx_p->pos); - literal_t lit = lit_get_literal_by_cp (lit_cp); - JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T); + lit_literal_t lit = lit_get_literal_by_cp (lit_cp); + JERRY_ASSERT (RCS_RECORD_IS_NUMBER (lit)); - *num_p = lit_charset_literal_get_number (lit); + *num_p = lit_number_literal_get_number (lit); ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, @@ -129,10 +131,10 @@ opfunc_assignment (vm_instr_t instr, /**< instruction */ lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (src_val_descr, frame_ctx_p->bytecode_header_p, frame_ctx_p->pos); - literal_t lit = lit_get_literal_by_cp (lit_cp); - JERRY_ASSERT (lit->get_type () == LIT_NUMBER_T); + lit_literal_t lit = lit_get_literal_by_cp (lit_cp); + JERRY_ASSERT (RCS_RECORD_IS_NUMBER (lit)); - *num_p = lit_charset_literal_get_number (lit); + *num_p = lit_number_literal_get_number (lit); ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, diff --git a/jerry-core/vm/pretty-printer.cpp b/jerry-core/vm/pretty-printer.cpp index 1845ff1444..d7b8ac23f3 100644 --- a/jerry-core/vm/pretty-printer.cpp +++ b/jerry-core/vm/pretty-printer.cpp @@ -64,7 +64,7 @@ clear_temp_buffer (void) static const char * lit_cp_to_str (lit_cpointer_t cp) { - literal_t lit = lit_get_literal_by_cp (cp); + lit_literal_t lit = lit_get_literal_by_cp (cp); return lit_literal_to_str_internal_buf (lit); } diff --git a/tests/unit/test-literal-storage.cpp b/tests/unit/test-literal-storage.cpp index d9830fe43c..e8160dae19 100644 --- a/tests/unit/test-literal-storage.cpp +++ b/tests/unit/test-literal-storage.cpp @@ -15,7 +15,8 @@ #include "ecma-helpers.h" #include "lit-literal.h" -#include "lit-magic-strings.h" +#include "lit-literal-storage.h" +#include "rcs-records.h" #include "test-common.h" // Iterations count @@ -68,7 +69,6 @@ main (int __attr_unused___ argc, mem_init (); lit_init (); - for (uint32_t i = 0; i < test_iters; i++) { memset (numbers, 0, sizeof (ecma_number_t) * test_sub_iters); @@ -108,8 +108,8 @@ main (int __attr_unused___ argc, for (uint32_t j = 0; j < test_sub_iters; j++) { - literal_t lit1; - literal_t lit2; + lit_literal_t lit1; + lit_literal_t lit2; if (ptrs[j]) { lit1 = lit_find_or_create_literal_from_utf8_string (ptrs[j], lengths[j]); @@ -133,8 +133,8 @@ main (int __attr_unused___ argc, // Check empty string exists JERRY_ASSERT (lit_find_literal_by_utf8_string (NULL, 0)); - lit_storage.cleanup (); - JERRY_ASSERT (lit_storage.get_first () == NULL); + rcs_lit_storage.cleanup (); + JERRY_ASSERT (rcs_record_get_first (&rcs_lit_storage) == NULL); } lit_finalize (); diff --git a/tests/unit/test-recordset.cpp b/tests/unit/test-recordset.cpp deleted file mode 100644 index 358bbc4c03..0000000000 --- a/tests/unit/test-recordset.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* Copyright 2015 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "mem-allocator.h" -#include "rcs-recordset.h" - -#include "test-common.h" - -// Heap size is 32K -#define test_heap_size (32 * 1024) - -// Iterations count -#define test_iters (64) - -// Subiterations count -#define test_sub_iters 64 - -// Threshold size of block to allocate -#define test_threshold_block_size 8192 - -// Maximum number of elements in a type-one record -#define test_max_type_one_record_elements 64 - -class test_rcs_record_type_one_t : public rcs_record_t -{ -public: - static size_t size (uint32_t elements_count) - { - return JERRY_ALIGNUP (header_size + element_size * elements_count, - RCS_DYN_STORAGE_LENGTH_UNIT); - } - - size_t get_size () const - { - return get_field (length_field_pos, length_field_width) * RCS_DYN_STORAGE_LENGTH_UNIT; - } - - void set_size (size_t size) - { - JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size); - - set_field (length_field_pos, length_field_width, size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG); - } - - rcs_record_t* get_prev () const - { - return get_pointer (prev_field_pos, prev_field_width); - } - - void set_prev (rcs_record_t* prev_rec_p) - { - set_pointer (prev_field_pos, prev_field_width, prev_rec_p); - } - - typedef uint16_t element_t; - - static const size_t header_size = 2 * RCS_DYN_STORAGE_LENGTH_UNIT; - static const size_t element_size = sizeof (test_rcs_record_type_one_t::element_t); -private: - static const uint32_t length_field_pos = _fields_offset_begin; - static const uint32_t length_field_width = 12u; - - static const uint32_t prev_field_pos = length_field_pos + length_field_width; - static const uint32_t prev_field_width = rcs_cpointer_t::bit_field_width; -}; - -class test_rcs_record_type_two_t : public rcs_record_t -{ -public: - static size_t size (void) - { - return JERRY_ALIGNUP (header_size, RCS_DYN_STORAGE_LENGTH_UNIT); - } - - size_t get_size () const - { - return size (); - } - - void set_size (size_t size) - { - JERRY_ASSERT (size == get_size ()); - } - - rcs_record_t* get_prev () const - { - return get_pointer (prev_field_pos, prev_field_width); - } - - void set_prev (rcs_record_t* prev_rec_p) - { - set_pointer (prev_field_pos, prev_field_width, prev_rec_p); - } - - static const size_t header_size = RCS_DYN_STORAGE_LENGTH_UNIT; -private: - static const uint32_t prev_field_pos = _fields_offset_begin; - static const uint32_t prev_field_width = rcs_cpointer_t::bit_field_width; -}; - -class test_rcs_recordset_t : public rcs_recordset_t -{ -public: - test_rcs_record_type_one_t* - create_record_type_one (uint32_t elements_count) - { - return alloc_record (_record_type_one_id, - elements_count); - } - - void - free_record_type_one (test_rcs_record_type_one_t* rec_p) - { - free_record (rec_p); - } - - test_rcs_record_type_two_t* - create_record_type_two (void) - { - return alloc_record (_record_type_two_id); - } - - void - free_record_type_two (test_rcs_record_type_two_t* rec_p) - { - free_record (rec_p); - } -private: - static const int _record_type_one_id = _first_type_id + 0; - static const int _record_type_two_id = _first_type_id + 1; - - virtual rcs_record_t* get_prev (rcs_record_t* rec_p) - { - switch (rec_p->get_type ()) - { - case _record_type_one_id: - { - return (static_cast (rec_p))->get_prev (); - } - case _record_type_two_id: - { - return (static_cast (rec_p))->get_prev (); - } - default: - { - JERRY_ASSERT (rec_p->get_type () < _first_type_id); - - return rcs_recordset_t::get_prev (rec_p); - } - } - } - - virtual void set_prev (rcs_record_t* rec_p, - rcs_record_t *prev_rec_p) - { - switch (rec_p->get_type ()) - { - case _record_type_one_id: - { - return (static_cast (rec_p))->set_prev (prev_rec_p); - } - case _record_type_two_id: - { - return (static_cast (rec_p))->set_prev (prev_rec_p); - } - default: - { - JERRY_ASSERT (rec_p->get_type () < _first_type_id); - - return rcs_recordset_t::set_prev (rec_p, prev_rec_p); - } - } - } - - virtual size_t get_record_size (rcs_record_t* rec_p) - { - switch (rec_p->get_type ()) - { - case _record_type_one_id: - { - return (static_cast (rec_p))->get_size (); - } - case _record_type_two_id: - { - return (static_cast (rec_p))->get_size (); - } - default: - { - JERRY_ASSERT (rec_p->get_type () < _first_type_id); - - return rcs_recordset_t::get_record_size (rec_p); - } - } - } -}; - -int -main (int __attr_unused___ argc, - char __attr_unused___ **argv) -{ - TEST_INIT (); - - mem_init (); - - test_rcs_recordset_t storage; - storage.init (); - - for (uint32_t i = 0; i < test_iters; i++) - { - test_rcs_record_type_one_t *type_one_records[test_sub_iters]; - uint32_t type_one_record_element_counts[test_sub_iters]; - test_rcs_record_type_one_t::element_t type_one_record_elements[test_sub_iters][test_max_type_one_record_elements]; - int type_one_records_number = 0; - - test_rcs_record_type_two_t *type_two_records[test_sub_iters]; - int type_two_records_number = 0; - - for (uint32_t j = 0; j < test_sub_iters; j++) - { - if (rand () % 2) - { - JERRY_ASSERT (type_one_records_number < test_sub_iters); - - uint32_t elements_count = ((uint32_t) rand ()) % test_max_type_one_record_elements; - type_one_record_element_counts[type_one_records_number] = elements_count; - type_one_records[type_one_records_number] = storage.create_record_type_one (elements_count); - - JERRY_ASSERT (type_one_records[type_one_records_number] != NULL); - - rcs_record_iterator_t it (&storage, type_one_records[type_one_records_number]); - it.skip (test_rcs_record_type_one_t::header_size); // skip header - for (uint32_t i = 0; - i < type_one_record_element_counts[type_one_records_number]; - it.skip(), i++) - { - test_rcs_record_type_one_t::element_t val = (test_rcs_record_type_one_t::element_t) rand (); - type_one_record_elements[type_one_records_number][i] = val; - it.write (val); - } - - JERRY_ASSERT (type_one_records[type_one_records_number] != NULL); - - it.reset (); - it.skip (test_rcs_record_type_one_t::header_size); // skip header - for (uint32_t i = 0; - i < type_one_record_element_counts[type_one_records_number]; - it.skip(), i++) - { - test_rcs_record_type_one_t::element_t val = type_one_record_elements[type_one_records_number][i]; - JERRY_ASSERT (val == it.read ()); - } - - type_one_records_number++; - } - else - { - JERRY_ASSERT (type_two_records_number < test_sub_iters); - - type_two_records[type_two_records_number] = storage.create_record_type_two (); - - JERRY_ASSERT (type_two_records[type_two_records_number] != NULL); - - type_two_records_number++; - } - } - - while (type_one_records_number + type_two_records_number != 0) - { - // Read test - for (int index_to_free = 0; index_to_free < type_one_records_number; index_to_free++) - { - JERRY_ASSERT (type_one_records_number > 0); - - JERRY_ASSERT (index_to_free >= 0 && index_to_free < type_one_records_number); - - rcs_record_iterator_t it (&storage, type_one_records[index_to_free]); - it.skip (test_rcs_record_type_one_t::header_size); // skip header - for (uint32_t i = 0; - i < type_one_record_element_counts[index_to_free]; - it.skip(), i++) - { - test_rcs_record_type_one_t::element_t val = type_one_record_elements[index_to_free][i]; - JERRY_ASSERT (it.read () == val); - } - - JERRY_ASSERT (JERRY_ALIGNUP (type_one_record_element_counts[index_to_free] - * sizeof (test_rcs_record_type_one_t::element_t) - + test_rcs_record_type_one_t::header_size, - RCS_DYN_STORAGE_LENGTH_UNIT) - == type_one_records[index_to_free]->get_size ()); - } - - bool free_type_one; - - if (type_one_records_number == 0) - { - JERRY_ASSERT (type_two_records_number != 0); - - free_type_one = false; - } - else if (type_two_records_number == 0) - { - JERRY_ASSERT (type_one_records_number != 0); - - free_type_one = true; - } - else - { - free_type_one = ((rand () % 2) != 0); - } - - if (free_type_one) - { - JERRY_ASSERT (type_one_records_number > 0); - int index_to_free = (rand () % type_one_records_number); - - JERRY_ASSERT (index_to_free >= 0 && index_to_free < type_one_records_number); - - rcs_record_iterator_t it (&storage, type_one_records[index_to_free]); - it.skip (test_rcs_record_type_one_t::header_size); // skip header - for (uint32_t i = 0; - i < type_one_record_element_counts[index_to_free]; - it.skip(), i++) - { - test_rcs_record_type_one_t::element_t val = type_one_record_elements[index_to_free][i]; - JERRY_ASSERT (it.read () == val); - } - - // free the record - storage.free_record_type_one (type_one_records[index_to_free]); - - type_one_records_number--; - while (index_to_free < type_one_records_number) - { - type_one_records[index_to_free] = type_one_records[index_to_free + 1]; - type_one_record_element_counts[index_to_free] = type_one_record_element_counts[index_to_free + 1]; - memcpy (type_one_record_elements[index_to_free], type_one_record_elements[index_to_free + 1], - test_max_type_one_record_elements * sizeof (test_rcs_record_type_one_t::element_t)); - - index_to_free++; - } - } - else - { - JERRY_ASSERT (type_two_records_number > 0); - int index_to_free = (rand () % type_two_records_number); - - JERRY_ASSERT (index_to_free >= 0 && index_to_free < type_two_records_number); - - storage.free_record_type_two (type_two_records[index_to_free]); - - type_two_records_number--; - while (index_to_free < type_two_records_number) - { - type_two_records[index_to_free] = type_two_records[index_to_free + 1]; - - index_to_free++; - } - } - } - } - - storage.finalize (); - - mem_finalize (true); - - return 0; -} /* main */ - -template test_rcs_record_type_one_t * -rcs_recordset_t::alloc_record (rcs_record_t::type_t, uint32_t); - -template test_rcs_record_type_two_t * -rcs_recordset_t::alloc_record (rcs_record_t::type_t);