jerryscript/jerry-core/rcs/rcs-records.c
Akos Kiss c9f5950e15 Replace bit field manipulation functions with macros
JerryScript-DCO-1.0-Signed-off-by: Akos Kiss akiss@inf.u-szeged.hu
2016-02-29 12:21:23 +01:00

638 lines
19 KiB
C

/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 = JRT_SET_BIT_FIELD_VALUE (uint32_t, 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.u.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.u.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_alignment_bytes_count */
/**
* 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 JRT_EXTRACT_BIT_FIELD (uint32_t, 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.u.value));
JERRY_ASSERT (sizeof (value) == sizeof (cpointer.u.value));
cpointer.u.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,
bits_in_rcs_record_type_t_must_be_greater_than_or_equal_to_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.u.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_node_t *first_node_p = rcs_chunked_list_get_first (rec_set_p);
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_node_t *node_p = rcs_chunked_list_get_node_from_pointer (rec_set_p, 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 = rcs_chunked_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 = rcs_chunked_list_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 */